5b55d09
diff -up openssh/auth2.c.gsskex openssh/auth2.c
bbf61da
--- openssh/auth2.c.gsskex	2018-08-22 11:47:33.260216045 +0200
bbf61da
+++ openssh/auth2.c	2018-08-22 11:47:33.307216424 +0200
bbf61da
@@ -74,6 +74,7 @@ extern Authmethod method_passwd;
535d341
 extern Authmethod method_kbdint;
535d341
 extern Authmethod method_hostbased;
535d341
 #ifdef GSSAPI
535d341
+extern Authmethod method_gsskeyex;
535d341
 extern Authmethod method_gssapi;
535d341
 #endif
535d341
 
bbf61da
@@ -81,6 +82,7 @@ Authmethod *authmethods[] = {
535d341
 	&method_none,
535d341
 	&method_pubkey,
535d341
 #ifdef GSSAPI
535d341
+	&method_gsskeyex,
535d341
 	&method_gssapi,
535d341
 #endif
535d341
 	&method_passwd,
5b55d09
diff -up openssh/auth2-gss.c.gsskex openssh/auth2-gss.c
bbf61da
--- openssh/auth2-gss.c.gsskex	2018-08-22 11:47:33.260216045 +0200
bbf61da
+++ openssh/auth2-gss.c	2018-08-22 13:00:48.722680124 +0200
580f986
@@ -31,6 +31,7 @@
580f986
 #include <sys/types.h>
580f986
 
580f986
 #include <stdarg.h>
580f986
+#include <string.h>
580f986
 
580f986
 #include "xmalloc.h"
bbf61da
 #include "sshkey.h"
90edc0c
@@ -54,6 +55,44 @@ static int input_gssapi_mic(int type, u_
5b55d09
 static int input_gssapi_exchange_complete(int type, u_int32_t plen, struct ssh *ssh);
5b55d09
 static int input_gssapi_errtok(int, u_int32_t, struct ssh *);
84822b5
 
84822b5
+/* 
84822b5
+ * The 'gssapi_keyex' userauth mechanism.
84822b5
+ */
84822b5
+static int
5b55d09
+userauth_gsskeyex(struct ssh *ssh)
84822b5
+{
5b55d09
+	Authctxt *authctxt = ssh->authctxt;
84822b5
+	int authenticated = 0;
bbf61da
+	struct sshbuf *b = NULL;
84822b5
+	gss_buffer_desc mic, gssbuf;
84822b5
+	u_int len;
51ca3be
+
84822b5
+	mic.value = packet_get_string(&len;;
84822b5
+	mic.length = len;
51ca3be
+
84822b5
+	packet_check_eom();
51ca3be
+
90edc0c
+	if ((b = sshbuf_new()) == NULL)
90edc0c
+		fatal("%s: sshbuf_new failed", __func__);
90edc0c
+
bbf61da
+	ssh_gssapi_buildmic(b, authctxt->user, authctxt->service,
84822b5
+	    "gssapi-keyex");
51ca3be
+
bbf61da
+	gssbuf.value = sshbuf_mutable_ptr(b);
bbf61da
+	gssbuf.length = sshbuf_len(b);
5039c7c
+
84822b5
+	/* gss_kex_context is NULL with privsep, so we can't check it here */
84822b5
+	if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gss_kex_context, 
84822b5
+	    &gssbuf, &mic))))
84822b5
+		authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user,
84822b5
+		    authctxt->pw));
84822b5
+	
bbf61da
+	sshbuf_free(b);
84822b5
+	free(mic.value);
5039c7c
+
84822b5
+	return (authenticated);
84822b5
+}
5039c7c
+
84822b5
 /*
84822b5
  * We only support those mechanisms that we know about (ie ones that we know
84822b5
  * how to check local user kuserok and the like)
bbf61da
@@ -260,7 +296,8 @@ input_gssapi_exchange_complete(int type,
bbf61da
 	if ((r = sshpkt_get_end(ssh)) != 0)
bbf61da
 		fatal("%s: %s", __func__, ssh_err(r));
84822b5
 
84822b5
-	authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user));
84822b5
+	authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user,
84822b5
+	    authctxt->pw));
84822b5
 
5b55d09
 	if ((!use_privsep || mm_is_monitor()) &&
5b55d09
 	    (displayname = ssh_gssapi_displayname()) != NULL)
bbf61da
@@ -313,7 +350,8 @@ input_gssapi_mic(int type, u_int32_t ple
bbf61da
 	gssbuf.length = sshbuf_len(b);
84822b5
 
84822b5
 	if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gssctxt, &gssbuf, &mic))))
84822b5
-		authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user));
84822b5
+		authenticated = 
84822b5
+		    PRIVSEP(ssh_gssapi_userok(authctxt->user, authctxt->pw));
84822b5
 	else
84822b5
 		logit("GSSAPI MIC check failed");
84822b5
 
bbf61da
@@ -335,6 +373,12 @@ input_gssapi_mic(int type, u_int32_t ple
132f8f8
 	return 0;
84822b5
 }
84822b5
 
84822b5
+Authmethod method_gsskeyex = {
84822b5
+	"gssapi-keyex",
84822b5
+	userauth_gsskeyex,
84822b5
+	&options.gss_authentication
84822b5
+};
5039c7c
+
84822b5
 Authmethod method_gssapi = {
84822b5
 	"gssapi-with-mic",
84822b5
 	userauth_gssapi,
5b55d09
diff -up openssh/auth.c.gsskex openssh/auth.c
bbf61da
--- openssh/auth.c.gsskex	2018-08-22 11:47:33.274216158 +0200
bbf61da
+++ openssh/auth.c	2018-08-22 11:47:33.308216432 +0200
bbf61da
@@ -395,6 +395,7 @@ auth_root_allowed(struct ssh *ssh, const
5b55d09
 	case PERMIT_NO_PASSWD:
5b55d09
 		if (strcmp(method, "publickey") == 0 ||
5b55d09
 		    strcmp(method, "hostbased") == 0 ||
5b55d09
+		    strcmp(method, "gssapi-keyex") == 0 ||
5b55d09
 		    strcmp(method, "gssapi-with-mic") == 0)
5b55d09
 			return 1;
5b55d09
 		break;
5b55d09
diff -up openssh/clientloop.c.gsskex openssh/clientloop.c
bbf61da
--- openssh/clientloop.c.gsskex	2018-08-20 07:57:29.000000000 +0200
bbf61da
+++ openssh/clientloop.c	2018-08-22 11:47:33.309216441 +0200
5b55d09
@@ -112,6 +112,10 @@
132f8f8
 #include "ssherr.h"
132f8f8
 #include "hostfile.h"
Jan F. Chadima 69dd72f
 
Jan F. Chadima 69dd72f
+#ifdef GSSAPI
Jan F. Chadima 69dd72f
+#include "ssh-gss.h"
Jan F. Chadima 69dd72f
+#endif
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
 /* import options */
Jan F. Chadima 69dd72f
 extern Options options;
Jan F. Chadima 69dd72f
 
bbf61da
@@ -1357,9 +1361,18 @@ client_loop(struct ssh *ssh, int have_pt
13073f8
 			break;
13073f8
 
Jan F. Chadima 69dd72f
 		/* Do channel operations unless rekeying in progress. */
5b55d09
-		if (!ssh_packet_is_rekeying(ssh))
5b55d09
+		if (!ssh_packet_is_rekeying(ssh)) {
5b55d09
 			channel_after_select(ssh, readset, writeset);
13073f8
 
Jan F. Chadima 69dd72f
+#ifdef GSSAPI
Jan F. Chadima 69dd72f
+			if (options.gss_renewal_rekey &&
6cf9b8e
+			    ssh_gssapi_credentials_updated(NULL)) {
Jan F. Chadima 69dd72f
+				debug("credentials updated - forcing rekey");
Jan F. Chadima 69dd72f
+				need_rekeying = 1;
Jan F. Chadima 69dd72f
+			}
Jan F. Chadima 69dd72f
+#endif
13073f8
+		}
Jan F. Chadima 69dd72f
+
13073f8
 		/* Buffer input from the connection.  */
13073f8
 		client_process_net_input(readset);
13073f8
 
5b55d09
diff -up openssh/configure.ac.gsskex openssh/configure.ac
bbf61da
--- openssh/configure.ac.gsskex	2018-08-22 11:47:33.296216335 +0200
bbf61da
+++ openssh/configure.ac	2018-08-22 11:47:33.309216441 +0200
bbf61da
@@ -673,6 +673,30 @@ main() { if (NSVersionOfRunTimeLibrary("
Jan F. Chadima 69dd72f
 	    [Use tunnel device compatibility to OpenBSD])
Jan F. Chadima 69dd72f
 	AC_DEFINE([SSH_TUN_PREPEND_AF], [1],
Jan F. Chadima 69dd72f
 	    [Prepend the address family to IP tunnel traffic])
Jan F. Chadima 69dd72f
+	AC_MSG_CHECKING(if we have the Security Authorization Session API)
Jan F. Chadima 69dd72f
+	AC_TRY_COMPILE([#include <Security/AuthSession.h>],
Jan F. Chadima 69dd72f
+		[SessionCreate(0, 0);],
Jan F. Chadima 69dd72f
+		[ac_cv_use_security_session_api="yes"
Jan F. Chadima 69dd72f
+		 AC_DEFINE(USE_SECURITY_SESSION_API, 1, 
Jan F. Chadima 69dd72f
+			[platform has the Security Authorization Session API])
Jan F. Chadima 69dd72f
+		 LIBS="$LIBS -framework Security"
Jan F. Chadima 69dd72f
+		 AC_MSG_RESULT(yes)],
Jan F. Chadima 69dd72f
+		[ac_cv_use_security_session_api="no"
Jan F. Chadima 69dd72f
+		 AC_MSG_RESULT(no)])
Jan F. Chadima 69dd72f
+	AC_MSG_CHECKING(if we have an in-memory credentials cache)
Jan F. Chadima 69dd72f
+	AC_TRY_COMPILE(
Jan F. Chadima 69dd72f
+		[#include <Kerberos/Kerberos.h>],
Jan F. Chadima 69dd72f
+		[cc_context_t c;
Jan F. Chadima 69dd72f
+		 (void) cc_initialize (&c, 0, NULL, NULL);],
Jan F. Chadima 69dd72f
+		[AC_DEFINE(USE_CCAPI, 1, 
Jan F. Chadima 69dd72f
+			[platform uses an in-memory credentials cache])
Jan F. Chadima 69dd72f
+		 LIBS="$LIBS -framework Security"
Jan F. Chadima 69dd72f
+		 AC_MSG_RESULT(yes)
Jan F. Chadima 69dd72f
+		 if test "x$ac_cv_use_security_session_api" = "xno"; then
Jan F. Chadima 69dd72f
+			AC_MSG_ERROR(*** Need a security framework to use the credentials cache API ***)
Jan F. Chadima 69dd72f
+		fi],
Jan F. Chadima 69dd72f
+		[AC_MSG_RESULT(no)]
Jan F. Chadima 69dd72f
+	)
Jan F. Chadima 69dd72f
 	m4_pattern_allow([AU_IPv])
5878ebb
 	AC_CHECK_DECL([AU_IPv4], [],
Jan F. Chadima 69dd72f
 	    AC_DEFINE([AU_IPv4], [0], [System only supports IPv4 audit records])
5b55d09
diff -up openssh/gss-genr.c.gsskex openssh/gss-genr.c
bbf61da
--- openssh/gss-genr.c.gsskex	2018-08-20 07:57:29.000000000 +0200
bbf61da
+++ openssh/gss-genr.c	2018-08-22 13:18:47.444383602 +0200
bbf61da
@@ -35,18 +35,177 @@
bbf61da
 #include <string.h>
bbf61da
 #include <signal.h>
bbf61da
 #include <unistd.h>
bbf61da
+#include <openssl/evp.h>
bbf61da
 
bbf61da
 #include "xmalloc.h"
bbf61da
 #include "ssherr.h"
bbf61da
 #include "sshbuf.h"
Jan F. Chadima 69dd72f
 #include "log.h"
Jan F. Chadima 69dd72f
 #include "ssh2.h"
Jan F. Chadima 69dd72f
+#include "cipher.h"
bbf61da
+#include "sshkey.h"
Jan F. Chadima 69dd72f
+#include "kex.h"
Jan F. Chadima 69dd72f
 
Jan F. Chadima 69dd72f
 #include "ssh-gss.h"
Jan F. Chadima 69dd72f
 
Jan F. Chadima 69dd72f
 extern u_char *session_id2;
Jan F. Chadima 69dd72f
 extern u_int session_id2_len;
Jan F. Chadima 69dd72f
 
Jan F. Chadima 69dd72f
+typedef struct {
Jan F. Chadima 69dd72f
+	char *encoded;
Jan F. Chadima 69dd72f
+	gss_OID oid;
Jan F. Chadima 69dd72f
+} ssh_gss_kex_mapping;
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+/*
Jan F. Chadima 69dd72f
+ * XXX - It would be nice to find a more elegant way of handling the
Jan F. Chadima 69dd72f
+ * XXX   passing of the key exchange context to the userauth routines
Jan F. Chadima 69dd72f
+ */
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+Gssctxt *gss_kex_context = NULL;
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+static ssh_gss_kex_mapping *gss_enc2oid = NULL;
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+int 
Jan F. Chadima 69dd72f
+ssh_gssapi_oid_table_ok() {
Jan F. Chadima 69dd72f
+	return (gss_enc2oid != NULL);
Jan F. Chadima 69dd72f
+}
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+/*
Jan F. Chadima 69dd72f
+ * Return a list of the gss-group1-sha1 mechanisms supported by this program
Jan F. Chadima 69dd72f
+ *
Jan F. Chadima 69dd72f
+ * We test mechanisms to ensure that we can use them, to avoid starting
Jan F. Chadima 69dd72f
+ * a key exchange with a bad mechanism
Jan F. Chadima 69dd72f
+ */
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+char *
Jan F. Chadima 69dd72f
+ssh_gssapi_client_mechanisms(const char *host, const char *client) {
Jan F. Chadima 69dd72f
+	gss_OID_set gss_supported;
Jan F. Chadima 69dd72f
+	OM_uint32 min_status;
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	if (GSS_ERROR(gss_indicate_mechs(&min_status, &gss_supported)))
Jan F. Chadima 69dd72f
+		return NULL;
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	return(ssh_gssapi_kex_mechs(gss_supported, ssh_gssapi_check_mechanism,
Jan F. Chadima 69dd72f
+	    host, client));
Jan F. Chadima 69dd72f
+}
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+char *
Jan F. Chadima 69dd72f
+ssh_gssapi_kex_mechs(gss_OID_set gss_supported, ssh_gssapi_check_fn *check,
Jan F. Chadima 69dd72f
+    const char *host, const char *client) {
bbf61da
+	struct sshbuf *buf;
Jan F. Chadima 69dd72f
+	size_t i;
bbf61da
+	int oidpos, enclen, r;
Jan F. Chadima 69dd72f
+	char *mechs, *encoded;
Jan F. Chadima 69dd72f
+	u_char digest[EVP_MAX_MD_SIZE];
Jan F. Chadima 69dd72f
+	char deroid[2];
Jan F. Chadima 69dd72f
+	const EVP_MD *evp_md = EVP_md5();
Jan F. Chadima 69dd72f
+	EVP_MD_CTX md;
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	if (gss_enc2oid != NULL) {
Jan F. Chadima 69dd72f
+		for (i = 0; gss_enc2oid[i].encoded != NULL; i++)
84822b5
+			free(gss_enc2oid[i].encoded);
84822b5
+		free(gss_enc2oid);
Jan F. Chadima 69dd72f
+	}
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	gss_enc2oid = xmalloc(sizeof(ssh_gss_kex_mapping) *
Jan F. Chadima 69dd72f
+	    (gss_supported->count + 1));
Jan F. Chadima 69dd72f
+
bbf61da
+	if ((buf = sshbuf_new()) == NULL)
bbf61da
+		fatal("%s: sshbuf_new failed", __func__);
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	oidpos = 0;
Jan F. Chadima 69dd72f
+	for (i = 0; i < gss_supported->count; i++) {
Jan F. Chadima 69dd72f
+		if (gss_supported->elements[i].length < 128 &&
Jan F. Chadima 69dd72f
+		    (*check)(NULL, &(gss_supported->elements[i]), host, client)) {
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+			deroid[0] = SSH_GSS_OIDTYPE;
Jan F. Chadima 69dd72f
+			deroid[1] = gss_supported->elements[i].length;
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+			EVP_DigestInit(&md, evp_md);
Jan F. Chadima 69dd72f
+			EVP_DigestUpdate(&md, deroid, 2);
Jan F. Chadima 69dd72f
+			EVP_DigestUpdate(&md,
Jan F. Chadima 69dd72f
+			    gss_supported->elements[i].elements,
Jan F. Chadima 69dd72f
+			    gss_supported->elements[i].length);
Jan F. Chadima 69dd72f
+			EVP_DigestFinal(&md, digest, NULL);
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+			encoded = xmalloc(EVP_MD_size(evp_md) * 2);
Jan F. Chadima 69dd72f
+			enclen = __b64_ntop(digest, EVP_MD_size(evp_md),
Jan F. Chadima 69dd72f
+			    encoded, EVP_MD_size(evp_md) * 2);
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+			if (oidpos != 0)
bbf61da
+				if ((r = sshbuf_put_u8(buf, ',')) != 0)
bbf61da
+					fatal("%s: buffer error: %s", __func__, ssh_err(r));
bbf61da
+
bbf61da
+			if ((r = sshbuf_put(buf, KEX_GSS_GEX_SHA1_ID,
bbf61da
+			    sizeof(KEX_GSS_GEX_SHA1_ID) - 1)) != 0 ||
bbf61da
+			    (r = sshbuf_put(buf, encoded, enclen)) != 0 ||
bbf61da
+			    (r = sshbuf_put_u8(buf, ',')) != 0 ||
bbf61da
+			    (r = sshbuf_put(buf, KEX_GSS_GRP1_SHA1_ID, 
bbf61da
+			    sizeof(KEX_GSS_GRP1_SHA1_ID) - 1)) != 0 ||
bbf61da
+			    (r = sshbuf_put(buf, encoded, enclen)) != 0 ||
bbf61da
+			    (r = sshbuf_put_u8(buf, ',')) != 0 ||
bbf61da
+			    (r = sshbuf_put(buf, KEX_GSS_GRP14_SHA1_ID,
bbf61da
+			    sizeof(KEX_GSS_GRP14_SHA1_ID) - 1)) != 0 ||
bbf61da
+			    (r = sshbuf_put(buf, encoded, enclen)) != 0)
bbf61da
+		 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+			gss_enc2oid[oidpos].oid = &(gss_supported->elements[i]);
Jan F. Chadima 69dd72f
+			gss_enc2oid[oidpos].encoded = encoded;
Jan F. Chadima 69dd72f
+			oidpos++;
Jan F. Chadima 69dd72f
+		}
Jan F. Chadima 69dd72f
+	}
Jan F. Chadima 69dd72f
+	gss_enc2oid[oidpos].oid = NULL;
Jan F. Chadima 69dd72f
+	gss_enc2oid[oidpos].encoded = NULL;
Jan F. Chadima 69dd72f
+
bbf61da
+	if ((r = sshbuf_put_u8(buf, '\0')) != 0)
bbf61da
+		fatal("%s: buffer error: %s", __func__, ssh_err(r));
Jan F. Chadima 69dd72f
+
bbf61da
+	mechs = xmalloc(sshbuf_len(buf));
bbf61da
+	sshbuf_get(buf, mechs, sshbuf_len(buf));
bbf61da
+	sshbuf_free(buf);
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	if (strlen(mechs) == 0) {
84822b5
+		free(mechs);
Jan F. Chadima 69dd72f
+		mechs = NULL;
Jan F. Chadima 69dd72f
+	}
bbf61da
+
Jan F. Chadima 69dd72f
+	return (mechs);
Jan F. Chadima 69dd72f
+}
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+gss_OID
Jan F. Chadima 69dd72f
+ssh_gssapi_id_kex(Gssctxt *ctx, char *name, int kex_type) {
Jan F. Chadima 69dd72f
+	int i = 0;
Jan F. Chadima 69dd72f
+	
Jan F. Chadima 69dd72f
+	switch (kex_type) {
Jan F. Chadima 69dd72f
+	case KEX_GSS_GRP1_SHA1:
Jan F. Chadima 69dd72f
+		if (strlen(name) < sizeof(KEX_GSS_GRP1_SHA1_ID))
Jan F. Chadima 69dd72f
+			return GSS_C_NO_OID;
Jan F. Chadima 69dd72f
+		name += sizeof(KEX_GSS_GRP1_SHA1_ID) - 1;
Jan F. Chadima 69dd72f
+		break;
Jan F. Chadima 69dd72f
+	case KEX_GSS_GRP14_SHA1:
Jan F. Chadima 69dd72f
+		if (strlen(name) < sizeof(KEX_GSS_GRP14_SHA1_ID))
Jan F. Chadima 69dd72f
+			return GSS_C_NO_OID;
Jan F. Chadima 69dd72f
+		name += sizeof(KEX_GSS_GRP14_SHA1_ID) - 1;
Jan F. Chadima 69dd72f
+		break;
Jan F. Chadima 69dd72f
+	case KEX_GSS_GEX_SHA1:
Jan F. Chadima 69dd72f
+		if (strlen(name) < sizeof(KEX_GSS_GEX_SHA1_ID))
Jan F. Chadima 69dd72f
+			return GSS_C_NO_OID;
Jan F. Chadima 69dd72f
+		name += sizeof(KEX_GSS_GEX_SHA1_ID) - 1;
Jan F. Chadima 69dd72f
+		break;
Jan F. Chadima 69dd72f
+	default:
Jan F. Chadima 69dd72f
+		return GSS_C_NO_OID;
Jan F. Chadima 69dd72f
+	}
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	while (gss_enc2oid[i].encoded != NULL &&
Jan F. Chadima 69dd72f
+	    strcmp(name, gss_enc2oid[i].encoded) != 0)
Jan F. Chadima 69dd72f
+		i++;
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	if (gss_enc2oid[i].oid != NULL && ctx != NULL)
Jan F. Chadima 69dd72f
+		ssh_gssapi_set_oid(ctx, gss_enc2oid[i].oid);
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	return gss_enc2oid[i].oid;
Jan F. Chadima 69dd72f
+}
Jan F. Chadima 69dd72f
+
bbf61da
 /* sshbuf_get for gss_buffer_desc */
Jan F. Chadima 69dd72f
 int
bbf61da
 ssh_gssapi_get_buffer_desc(struct sshbuf *b, gss_buffer_desc *g)
bbf61da
@@ -218,7 +373,7 @@ ssh_gssapi_init_ctx(Gssctxt *ctx, int de
Jan F. Chadima 69dd72f
 	}
Jan F. Chadima 69dd72f
 
Jan F. Chadima 69dd72f
 	ctx->major = gss_init_sec_context(&ctx->minor,
Jan F. Chadima 69dd72f
-	    GSS_C_NO_CREDENTIAL, &ctx->context, ctx->name, ctx->oid,
Jan F. Chadima 69dd72f
+	    ctx->client_creds, &ctx->context, ctx->name, ctx->oid,
Jan F. Chadima 69dd72f
 	    GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG | deleg_flag,
Jan F. Chadima 69dd72f
 	    0, NULL, recv_tok, NULL, send_tok, flags, NULL);
Jan F. Chadima 69dd72f
 
bbf61da
@@ -248,8 +403,42 @@ ssh_gssapi_import_name(Gssctxt *ctx, con
Jan F. Chadima 69dd72f
 }
Jan F. Chadima 69dd72f
 
Jan F. Chadima 69dd72f
 OM_uint32
Jan F. Chadima 69dd72f
+ssh_gssapi_client_identity(Gssctxt *ctx, const char *name)
Jan F. Chadima 69dd72f
+{
Jan F. Chadima 69dd72f
+	gss_buffer_desc gssbuf;
Jan F. Chadima 69dd72f
+	gss_name_t gssname;
Jan F. Chadima 69dd72f
+	OM_uint32 status;
Jan F. Chadima 69dd72f
+	gss_OID_set oidset;
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	gssbuf.value = (void *) name;
Jan F. Chadima 69dd72f
+	gssbuf.length = strlen(gssbuf.value);
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	gss_create_empty_oid_set(&status, &oidset);
Jan F. Chadima 69dd72f
+	gss_add_oid_set_member(&status, ctx->oid, &oidset);
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	ctx->major = gss_import_name(&ctx->minor, &gssbuf,
Jan F. Chadima 69dd72f
+	    GSS_C_NT_USER_NAME, &gssname);
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	if (!ctx->major)
Jan F. Chadima 69dd72f
+		ctx->major = gss_acquire_cred(&ctx->minor, 
Jan F. Chadima 69dd72f
+		    gssname, 0, oidset, GSS_C_INITIATE, 
Jan F. Chadima 69dd72f
+		    &ctx->client_creds, NULL, NULL);
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	gss_release_name(&status, &gssname);
Jan F. Chadima 69dd72f
+	gss_release_oid_set(&status, &oidset);
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	if (ctx->major)
Jan F. Chadima 69dd72f
+		ssh_gssapi_error(ctx);
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	return(ctx->major);
Jan F. Chadima 69dd72f
+}
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+OM_uint32
Jan F. Chadima 69dd72f
 ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash)
Jan F. Chadima 69dd72f
 {
Jan F. Chadima 69dd72f
+	if (ctx == NULL) 
Jan F. Chadima 69dd72f
+		return -1;
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
 	if ((ctx->major = gss_get_mic(&ctx->minor, ctx->context,
Jan F. Chadima 69dd72f
 	    GSS_C_QOP_DEFAULT, buffer, hash)))
Jan F. Chadima 69dd72f
 		ssh_gssapi_error(ctx);
bbf61da
@@ -257,6 +446,19 @@ ssh_gssapi_sign(Gssctxt *ctx, gss_buffer
Jan F. Chadima 69dd72f
 	return (ctx->major);
Jan F. Chadima 69dd72f
 }
Jan F. Chadima 69dd72f
 
Jan F. Chadima 69dd72f
+/* Priviledged when used by server */
Jan F. Chadima 69dd72f
+OM_uint32
Jan F. Chadima 69dd72f
+ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic)
Jan F. Chadima 69dd72f
+{
Jan F. Chadima 69dd72f
+	if (ctx == NULL)
Jan F. Chadima 69dd72f
+		return -1;
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	ctx->major = gss_verify_mic(&ctx->minor, ctx->context,
Jan F. Chadima 69dd72f
+	    gssbuf, gssmic, NULL);
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	return (ctx->major);
Jan F. Chadima 69dd72f
+}
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
 void
bbf61da
 ssh_gssapi_buildmic(struct sshbuf *b, const char *user, const char *service,
Jan F. Chadima 69dd72f
     const char *context)
bbf61da
@@ -273,11 +475,16 @@ ssh_gssapi_buildmic(struct sshbuf *b, co
Jan F. Chadima 69dd72f
 }
Jan F. Chadima 69dd72f
 
Jan F. Chadima 69dd72f
 int
Jan F. Chadima 69dd72f
-ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host)
Jan F. Chadima 69dd72f
+ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host, 
Jan F. Chadima 69dd72f
+    const char *client)
Jan F. Chadima 69dd72f
 {
Jan F. Chadima 69dd72f
 	gss_buffer_desc token = GSS_C_EMPTY_BUFFER;
Jan F. Chadima 69dd72f
 	OM_uint32 major, minor;
Jan F. Chadima 69dd72f
 	gss_OID_desc spnego_oid = {6, (void *)"\x2B\x06\x01\x05\x05\x02"};
Jan F. Chadima 69dd72f
+	Gssctxt *intctx = NULL;
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	if (ctx == NULL)
Jan F. Chadima 69dd72f
+		ctx = &intct;;
Jan F. Chadima 69dd72f
 
Jan F. Chadima 69dd72f
 	/* RFC 4462 says we MUST NOT do SPNEGO */
Jan F. Chadima 69dd72f
 	if (oid->length == spnego_oid.length && 
bbf61da
@@ -287,6 +494,10 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx
Jan F. Chadima 69dd72f
 	ssh_gssapi_build_ctx(ctx);
Jan F. Chadima 69dd72f
 	ssh_gssapi_set_oid(*ctx, oid);
Jan F. Chadima 69dd72f
 	major = ssh_gssapi_import_name(*ctx, host);
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	if (!GSS_ERROR(major) && client)
Jan F. Chadima 69dd72f
+		major = ssh_gssapi_client_identity(*ctx, client);
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
 	if (!GSS_ERROR(major)) {
Jan F. Chadima 69dd72f
 		major = ssh_gssapi_init_ctx(*ctx, 0, GSS_C_NO_BUFFER, &token, 
Jan F. Chadima 69dd72f
 		    NULL);
bbf61da
@@ -296,10 +507,66 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx
Jan F. Chadima 69dd72f
 			    GSS_C_NO_BUFFER);
Jan F. Chadima 69dd72f
 	}
Jan F. Chadima 69dd72f
 
Jan F. Chadima 69dd72f
-	if (GSS_ERROR(major)) 
Jan F. Chadima 69dd72f
+	if (GSS_ERROR(major) || intctx != NULL) 
Jan F. Chadima 69dd72f
 		ssh_gssapi_delete_ctx(ctx);
Jan F. Chadima 69dd72f
 
84822b5
 	return (!GSS_ERROR(major));
84822b5
 }
84822b5
 
84822b5
+int
84822b5
+ssh_gssapi_credentials_updated(Gssctxt *ctxt) {
84822b5
+	static gss_name_t saved_name = GSS_C_NO_NAME;
84822b5
+	static OM_uint32 saved_lifetime = 0;
84822b5
+	static gss_OID saved_mech = GSS_C_NO_OID;
84822b5
+	static gss_name_t name;
84822b5
+	static OM_uint32 last_call = 0;
84822b5
+	OM_uint32 lifetime, now, major, minor;
84822b5
+	int equal;
84822b5
+	
84822b5
+	now = time(NULL);
84822b5
+
84822b5
+	if (ctxt) {
84822b5
+		debug("Rekey has happened - updating saved versions");
84822b5
+
84822b5
+		if (saved_name != GSS_C_NO_NAME)
84822b5
+			gss_release_name(&minor, &saved_name);
84822b5
+
84822b5
+		major = gss_inquire_cred(&minor, GSS_C_NO_CREDENTIAL,
84822b5
+		    &saved_name, &saved_lifetime, NULL, NULL);
84822b5
+
84822b5
+		if (!GSS_ERROR(major)) {
84822b5
+			saved_mech = ctxt->oid;
84822b5
+		        saved_lifetime+= now;
84822b5
+		} else {
84822b5
+			/* Handle the error */
84822b5
+		}
84822b5
+		return 0;
84822b5
+	}
84822b5
+
84822b5
+	if (now - last_call < 10)
84822b5
+		return 0;
84822b5
+
84822b5
+	last_call = now;
84822b5
+
84822b5
+	if (saved_mech == GSS_C_NO_OID)
84822b5
+		return 0;
84822b5
+	
84822b5
+	major = gss_inquire_cred(&minor, GSS_C_NO_CREDENTIAL, 
84822b5
+	    &name, &lifetime, NULL, NULL);
84822b5
+	if (major == GSS_S_CREDENTIALS_EXPIRED)
84822b5
+		return 0;
84822b5
+	else if (GSS_ERROR(major))
84822b5
+		return 0;
84822b5
+
84822b5
+	major = gss_compare_name(&minor, saved_name, name, &equal);
84822b5
+	gss_release_name(&minor, &name);
84822b5
+	if (GSS_ERROR(major))
84822b5
+		return 0;
84822b5
+
84822b5
+	if (equal && (saved_lifetime < lifetime + now - 10))
84822b5
+		return 1;
84822b5
+
84822b5
+	return 0;
84822b5
+}
84822b5
+
84822b5
 #endif /* GSSAPI */
5b55d09
diff -up openssh/gss-serv.c.gsskex openssh/gss-serv.c
bbf61da
--- openssh/gss-serv.c.gsskex	2018-08-20 07:57:29.000000000 +0200
bbf61da
+++ openssh/gss-serv.c	2018-08-22 11:47:33.310216448 +0200
bbf61da
@@ -44,17 +44,19 @@
Jan F. Chadima 69dd72f
 #include "session.h"
Jan F. Chadima 69dd72f
 #include "misc.h"
535d341
 #include "servconf.h"
Jan F. Chadima 69dd72f
+#include "uidswap.h"
Jan F. Chadima 69dd72f
 
Jan F. Chadima 69dd72f
 #include "ssh-gss.h"
Jan F. Chadima 69dd72f
+#include "monitor_wrap.h"
535d341
 
535d341
 extern ServerOptions options;
Jan F. Chadima 69dd72f
 
Jan F. Chadima 69dd72f
 static ssh_gssapi_client gssapi_client =
6cf9b8e
-    { GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER,
84822b5
-    GSS_C_NO_CREDENTIAL, NULL, {NULL, NULL, NULL, NULL}};
6cf9b8e
+    { GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER, GSS_C_NO_CREDENTIAL,
1176788
+    GSS_C_NO_NAME, NULL, {NULL, NULL, NULL, NULL}, 0, 0};
Jan F. Chadima 69dd72f
 
Jan F. Chadima 69dd72f
 ssh_gssapi_mech gssapi_null_mech =
Jan F. Chadima 69dd72f
-    { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL};
Jan F. Chadima 69dd72f
+    { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL, NULL};
Jan F. Chadima 69dd72f
 
Jan F. Chadima 69dd72f
 #ifdef KRB5
Jan F. Chadima 69dd72f
 extern ssh_gssapi_mech gssapi_kerberos_mech;
bbf61da
@@ -141,6 +143,28 @@ ssh_gssapi_server_ctx(Gssctxt **ctx, gss
Jan F. Chadima 69dd72f
 }
Jan F. Chadima 69dd72f
 
Jan F. Chadima 69dd72f
 /* Unprivileged */
Jan F. Chadima 69dd72f
+char *
Jan F. Chadima 69dd72f
+ssh_gssapi_server_mechanisms() {
4189ceb
+	if (supported_oids == NULL)
4189ceb
+		ssh_gssapi_prepare_supported_oids();
4189ceb
+	return (ssh_gssapi_kex_mechs(supported_oids,
4189ceb
+	    &ssh_gssapi_server_check_mech, NULL, NULL));
Jan F. Chadima 69dd72f
+}
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+/* Unprivileged */
Jan F. Chadima 69dd72f
+int
Jan F. Chadima 69dd72f
+ssh_gssapi_server_check_mech(Gssctxt **dum, gss_OID oid, const char *data,
Jan F. Chadima 69dd72f
+    const char *dummy) {
Jan F. Chadima 69dd72f
+	Gssctxt *ctx = NULL;
Jan F. Chadima 69dd72f
+	int res;
Jan F. Chadima 69dd72f
+ 
Jan F. Chadima 69dd72f
+	res = !GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctx, oid)));
Jan F. Chadima 69dd72f
+	ssh_gssapi_delete_ctx(&ctx;;
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	return (res);
Jan F. Chadima 69dd72f
+}
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+/* Unprivileged */
Jan F. Chadima 69dd72f
 void
Jan F. Chadima 69dd72f
 ssh_gssapi_supported_oids(gss_OID_set *oidset)
Jan F. Chadima 69dd72f
 {
bbf61da
@@ -150,7 +174,9 @@ ssh_gssapi_supported_oids(gss_OID_set *o
Jan F. Chadima 69dd72f
 	gss_OID_set supported;
Jan F. Chadima 69dd72f
 
Jan F. Chadima 69dd72f
 	gss_create_empty_oid_set(&min_status, oidset);
Jan F. Chadima 69dd72f
-	gss_indicate_mechs(&min_status, &supported);
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	if (GSS_ERROR(gss_indicate_mechs(&min_status, &supported)))
Jan F. Chadima 69dd72f
+		return;
Jan F. Chadima 69dd72f
 
Jan F. Chadima 69dd72f
 	while (supported_mechs[i]->name != NULL) {
Jan F. Chadima 69dd72f
 		if (GSS_ERROR(gss_test_oid_set_member(&min_status,
bbf61da
@@ -276,8 +302,48 @@ OM_uint32
Jan F. Chadima 69dd72f
 ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client)
Jan F. Chadima 69dd72f
 {
Jan F. Chadima 69dd72f
 	int i = 0;
Jan F. Chadima 69dd72f
+	int equal = 0;
Jan F. Chadima 69dd72f
+	gss_name_t new_name = GSS_C_NO_NAME;
Jan F. Chadima 69dd72f
+	gss_buffer_desc ename = GSS_C_EMPTY_BUFFER;
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	if (options.gss_store_rekey && client->used && ctx->client_creds) {
Jan F. Chadima 69dd72f
+		if (client->mech->oid.length != ctx->oid->length ||
Jan F. Chadima 69dd72f
+		    (memcmp(client->mech->oid.elements,
Jan F. Chadima 69dd72f
+		     ctx->oid->elements, ctx->oid->length) !=0)) {
Jan F. Chadima 69dd72f
+			debug("Rekeyed credentials have different mechanism");
Jan F. Chadima 69dd72f
+			return GSS_S_COMPLETE;
Jan F. Chadima 69dd72f
+		}
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+		if ((ctx->major = gss_inquire_cred_by_mech(&ctx->minor, 
Jan F. Chadima 69dd72f
+		    ctx->client_creds, ctx->oid, &new_name, 
Jan F. Chadima 69dd72f
+		    NULL, NULL, NULL))) {
Jan F. Chadima 69dd72f
+			ssh_gssapi_error(ctx);
Jan F. Chadima 69dd72f
+			return (ctx->major);
Jan F. Chadima 69dd72f
+		}
5b55d09
+
Jan F. Chadima 69dd72f
+		ctx->major = gss_compare_name(&ctx->minor, client->name, 
Jan F. Chadima 69dd72f
+		    new_name, &equal);
1900351
+
Jan F. Chadima 69dd72f
+		if (GSS_ERROR(ctx->major)) {
Jan F. Chadima 69dd72f
+			ssh_gssapi_error(ctx);
Jan F. Chadima 69dd72f
+			return (ctx->major);
Jan F. Chadima 69dd72f
+		}
Jan F. Chadima 69dd72f
+ 
Jan F. Chadima 69dd72f
+		if (!equal) {
Jan F. Chadima 69dd72f
+			debug("Rekeyed credentials have different name");
Jan F. Chadima 69dd72f
+			return GSS_S_COMPLETE;
Jan F. Chadima 69dd72f
+		}
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+		debug("Marking rekeyed credentials for export");
5b55d09
 
5b55d09
-	gss_buffer_desc ename;
Jan F. Chadima 69dd72f
+		gss_release_name(&ctx->minor, &client->name);
Jan F. Chadima 69dd72f
+		gss_release_cred(&ctx->minor, &client->creds);
Jan F. Chadima 69dd72f
+		client->name = new_name;
Jan F. Chadima 69dd72f
+		client->creds = ctx->client_creds;
Jan F. Chadima 69dd72f
+        	ctx->client_creds = GSS_C_NO_CREDENTIAL;
Jan F. Chadima 69dd72f
+		client->updated = 1;
Jan F. Chadima 69dd72f
+		return GSS_S_COMPLETE;
Jan F. Chadima 69dd72f
+	}
Jan F. Chadima 69dd72f
 
Jan F. Chadima 69dd72f
 	client->mech = NULL;
Jan F. Chadima 69dd72f
 
bbf61da
@@ -292,6 +358,13 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_g
Jan F. Chadima 69dd72f
 	if (client->mech == NULL)
Jan F. Chadima 69dd72f
 		return GSS_S_FAILURE;
Jan F. Chadima 69dd72f
 
Jan F. Chadima 69dd72f
+	if (ctx->client_creds &&
Jan F. Chadima 69dd72f
+	    (ctx->major = gss_inquire_cred_by_mech(&ctx->minor,
Jan F. Chadima 69dd72f
+	     ctx->client_creds, ctx->oid, &client->name, NULL, NULL, NULL))) {
Jan F. Chadima 69dd72f
+		ssh_gssapi_error(ctx);
Jan F. Chadima 69dd72f
+		return (ctx->major);
Jan F. Chadima 69dd72f
+	}
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
 	if ((ctx->major = gss_display_name(&ctx->minor, ctx->client,
Jan F. Chadima 69dd72f
 	    &client->displayname, NULL))) {
Jan F. Chadima 69dd72f
 		ssh_gssapi_error(ctx);
bbf61da
@@ -309,6 +382,8 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_g
Jan F. Chadima 69dd72f
 		return (ctx->major);
Jan F. Chadima 69dd72f
 	}
Jan F. Chadima 69dd72f
 
Jan F. Chadima 69dd72f
+	gss_release_buffer(&ctx->minor, &ename);
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
 	/* We can't copy this structure, so we just move the pointer to it */
Jan F. Chadima 69dd72f
 	client->creds = ctx->client_creds;
Jan F. Chadima 69dd72f
 	ctx->client_creds = GSS_C_NO_CREDENTIAL;
bbf61da
@@ -319,11 +394,20 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_g
51ca3be
 void
51ca3be
 ssh_gssapi_cleanup_creds(void)
51ca3be
 {
99076b0
-	if (gssapi_client.store.filename != NULL) {
99076b0
-		/* Unlink probably isn't sufficient */
99076b0
-		debug("removing gssapi cred file\"%s\"",
99076b0
-		    gssapi_client.store.filename);
99076b0
-		unlink(gssapi_client.store.filename);
99076b0
+	krb5_ccache ccache = NULL;
99076b0
+	krb5_error_code problem;
99076b0
+
99076b0
+	if (gssapi_client.store.data != NULL) {
99076b0
+		if ((problem = krb5_cc_resolve(gssapi_client.store.data, gssapi_client.store.envval, &ccache))) {
99076b0
+			debug("%s: krb5_cc_resolve(): %.100s", __func__,
99076b0
+				krb5_get_err_text(gssapi_client.store.data, problem));
99076b0
+		} else if ((problem = krb5_cc_destroy(gssapi_client.store.data, ccache))) {
99076b0
+			debug("%s: krb5_cc_resolve(): %.100s", __func__,
99076b0
+				krb5_get_err_text(gssapi_client.store.data, problem));
99076b0
+		} else {
99076b0
+			krb5_free_context(gssapi_client.store.data);
99076b0
+			gssapi_client.store.data = NULL;
51ca3be
+		}
51ca3be
 	}
51ca3be
 }
51ca3be
 
bbf61da
@@ -356,7 +440,7 @@ ssh_gssapi_do_child(char ***envp, u_int
Jan F. Chadima 69dd72f
 
Jan F. Chadima 69dd72f
 /* Privileged */
Jan F. Chadima 69dd72f
 int
Jan F. Chadima 69dd72f
-ssh_gssapi_userok(char *user)
Jan F. Chadima 69dd72f
+ssh_gssapi_userok(char *user, struct passwd *pw)
Jan F. Chadima 69dd72f
 {
Jan F. Chadima 69dd72f
 	OM_uint32 lmin;
Jan F. Chadima 69dd72f
 
bbf61da
@@ -366,9 +450,11 @@ ssh_gssapi_userok(char *user)
Jan F. Chadima 69dd72f
 		return 0;
Jan F. Chadima 69dd72f
 	}
Jan F. Chadima 69dd72f
 	if (gssapi_client.mech && gssapi_client.mech->userok)
Jan F. Chadima 69dd72f
-		if ((*gssapi_client.mech->userok)(&gssapi_client, user))
Jan F. Chadima 69dd72f
+		if ((*gssapi_client.mech->userok)(&gssapi_client, user)) {
Jan F. Chadima 69dd72f
+			gssapi_client.used = 1;
Jan F. Chadima 69dd72f
+			gssapi_client.store.owner = pw;
Jan F. Chadima 69dd72f
 			return 1;
Jan F. Chadima 69dd72f
-		else {
Jan F. Chadima 69dd72f
+		} else {
Jan F. Chadima 69dd72f
 			/* Destroy delegated credentials if userok fails */
Jan F. Chadima 69dd72f
 			gss_release_buffer(&lmin, &gssapi_client.displayname);
Jan F. Chadima 69dd72f
 			gss_release_buffer(&lmin, &gssapi_client.exportedname);
bbf61da
@@ -382,14 +468,89 @@ ssh_gssapi_userok(char *user)
Jan F. Chadima 69dd72f
 	return (0);
Jan F. Chadima 69dd72f
 }
Jan F. Chadima 69dd72f
 
Jan F. Chadima 69dd72f
-/* Privileged */
Jan F. Chadima 69dd72f
-OM_uint32
Jan F. Chadima 69dd72f
-ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic)
Jan F. Chadima 69dd72f
+/* These bits are only used for rekeying. The unpriviledged child is running 
Jan F. Chadima 69dd72f
+ * as the user, the monitor is root.
Jan F. Chadima 69dd72f
+ *
Jan F. Chadima 69dd72f
+ * In the child, we want to :
Jan F. Chadima 69dd72f
+ *    *) Ask the monitor to store our credentials into the store we specify
Jan F. Chadima 69dd72f
+ *    *) If it succeeds, maybe do a PAM update
Jan F. Chadima 69dd72f
+ */
Jan F. Chadima 69dd72f
+
d9e6186
+/* Stuff for PAM */
d9e6186
+
d9e6186
+#ifdef USE_PAM
d9e6186
+static int ssh_gssapi_simple_conv(int n, const struct pam_message **msg, 
d9e6186
+    struct pam_response **resp, void *data)
d9e6186
 {
d9e6186
-	ctx->major = gss_verify_mic(&ctx->minor, ctx->context,
d9e6186
-	    gssbuf, gssmic, NULL);
d9e6186
+	return (PAM_CONV_ERR);
d9e6186
+}
d9e6186
+#endif
d9e6186
 
d9e6186
-	return (ctx->major);
d9e6186
+void
d9e6186
+ssh_gssapi_rekey_creds() {
d9e6186
+	int ok;
d9e6186
+	int ret;
d9e6186
+#ifdef USE_PAM
d9e6186
+	pam_handle_t *pamh = NULL;
d9e6186
+	struct pam_conv pamconv = {ssh_gssapi_simple_conv, NULL};
d9e6186
+	char *envstr;
d9e6186
+#endif
d9e6186
+
1176788
+	if (gssapi_client.store.envval == NULL &&
d9e6186
+	    gssapi_client.store.envvar == NULL)
d9e6186
+		return;
d9e6186
+ 
d9e6186
+	ok = PRIVSEP(ssh_gssapi_update_creds(&gssapi_client.store));
d9e6186
+
d9e6186
+	if (!ok)
d9e6186
+		return;
d9e6186
+
d9e6186
+	debug("Rekeyed credentials stored successfully");
d9e6186
+
d9e6186
+	/* Actually managing to play with the ssh pam stack from here will
d9e6186
+	 * be next to impossible. In any case, we may want different options
d9e6186
+	 * for rekeying. So, use our own :)
d9e6186
+	 */
d9e6186
+#ifdef USE_PAM	
d9e6186
+	if (!use_privsep) {
d9e6186
+		debug("Not even going to try and do PAM with privsep disabled");
d9e6186
+		return;
d9e6186
+	}
d9e6186
+
d9e6186
+	ret = pam_start("sshd-rekey", gssapi_client.store.owner->pw_name,
d9e6186
+ 	    &pamconv, &pamh);
d9e6186
+	if (ret)
d9e6186
+		return;
d9e6186
+
d9e6186
+	xasprintf(&envstr, "%s=%s", gssapi_client.store.envvar, 
d9e6186
+	    gssapi_client.store.envval);
d9e6186
+
d9e6186
+	ret = pam_putenv(pamh, envstr);
d9e6186
+	if (!ret)
d9e6186
+		pam_setcred(pamh, PAM_REINITIALIZE_CRED);
d9e6186
+	pam_end(pamh, PAM_SUCCESS);
d9e6186
+#endif
d9e6186
+}
d9e6186
+
d9e6186
+int 
d9e6186
+ssh_gssapi_update_creds(ssh_gssapi_ccache *store) {
d9e6186
+	int ok = 0;
d9e6186
+
d9e6186
+	/* Check we've got credentials to store */
d9e6186
+	if (!gssapi_client.updated)
d9e6186
+		return 0;
d9e6186
+
d9e6186
+	gssapi_client.updated = 0;
d9e6186
+
d9e6186
+	temporarily_use_uid(gssapi_client.store.owner);
d9e6186
+	if (gssapi_client.mech && gssapi_client.mech->updatecreds)
d9e6186
+		ok = (*gssapi_client.mech->updatecreds)(store, &gssapi_client);
d9e6186
+	else
d9e6186
+		debug("No update function for this mechanism");
d9e6186
+
d9e6186
+	restore_uid();
d9e6186
+
d9e6186
+	return ok;
d9e6186
 }
d9e6186
 
5b55d09
 /* Privileged */
5b55d09
diff -up openssh/gss-serv-krb5.c.gsskex openssh/gss-serv-krb5.c
bbf61da
--- openssh/gss-serv-krb5.c.gsskex	2018-08-20 07:57:29.000000000 +0200
bbf61da
+++ openssh/gss-serv-krb5.c	2018-08-22 11:47:33.311216457 +0200
bbf61da
@@ -120,7 +120,7 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_cl
535d341
 	krb5_error_code problem;
535d341
 	krb5_principal princ;
535d341
 	OM_uint32 maj_status, min_status;
535d341
-	int len;
535d341
+	const char *new_ccname, *new_cctype;
535d341
 	const char *errmsg;
535d341
 
535d341
 	if (client->creds == NULL) {
bbf61da
@@ -180,11 +180,23 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_cl
535d341
 		return;
535d341
 	}
535d341
 
535d341
-	client->store.filename = xstrdup(krb5_cc_get_name(krb_context, ccache));
535d341
+	new_cctype = krb5_cc_get_type(krb_context, ccache);
535d341
+	new_ccname = krb5_cc_get_name(krb_context, ccache);
535d341
+
535d341
 	client->store.envvar = "KRB5CCNAME";
535d341
-	len = strlen(client->store.filename) + 6;
535d341
-	client->store.envval = xmalloc(len);
535d341
-	snprintf(client->store.envval, len, "FILE:%s", client->store.filename);
535d341
+#ifdef USE_CCAPI
535d341
+	xasprintf(&client->store.envval, "API:%s", new_ccname);
535d341
+#else
535d341
+	if (new_ccname[0] == ':')
535d341
+		new_ccname++;
535d341
+	xasprintf(&client->store.envval, "%s:%s", new_cctype, new_ccname);
535d341
+	if (strcmp(new_cctype, "DIR") == 0) {
535d341
+		char *p;
535d341
+		p = strrchr(client->store.envval, '/');
535d341
+		if (p)
535d341
+			*p = '\0';
535d341
+	}
535d341
+#endif
535d341
 
535d341
 #ifdef USE_PAM
535d341
 	if (options.use_pam)
bbf61da
@@ -193,9 +205,76 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_cl
535d341
 
535d341
 	krb5_cc_close(krb_context, ccache);
535d341
 
535d341
+	client->store.data = krb_context;
535d341
+
535d341
 	return;
535d341
 }
535d341
 
535d341
+int
535d341
+ssh_gssapi_krb5_updatecreds(ssh_gssapi_ccache *store, 
535d341
+    ssh_gssapi_client *client)
535d341
+{
535d341
+	krb5_ccache ccache = NULL;
535d341
+	krb5_principal principal = NULL;
535d341
+	char *name = NULL;
535d341
+	krb5_error_code problem;
535d341
+	OM_uint32 maj_status, min_status;
535d341
+
535d341
+   	if ((problem = krb5_cc_resolve(krb_context, store->envval, &ccache))) {
535d341
+                logit("krb5_cc_resolve(): %.100s",
535d341
+                    krb5_get_err_text(krb_context, problem));
535d341
+                return 0;
535d341
+       	}
535d341
+	
535d341
+	/* Find out who the principal in this cache is */
535d341
+	if ((problem = krb5_cc_get_principal(krb_context, ccache, 
535d341
+	    &principal))) {
535d341
+		logit("krb5_cc_get_principal(): %.100s",
535d341
+		    krb5_get_err_text(krb_context, problem));
535d341
+		krb5_cc_close(krb_context, ccache);
535d341
+		return 0;
535d341
+	}
535d341
+
535d341
+	if ((problem = krb5_unparse_name(krb_context, principal, &name))) {
535d341
+		logit("krb5_unparse_name(): %.100s",
535d341
+		    krb5_get_err_text(krb_context, problem));
535d341
+		krb5_free_principal(krb_context, principal);
535d341
+		krb5_cc_close(krb_context, ccache);
535d341
+		return 0;
535d341
+	}
535d341
+
535d341
+
535d341
+	if (strcmp(name,client->exportedname.value)!=0) {
535d341
+		debug("Name in local credentials cache differs. Not storing");
535d341
+		krb5_free_principal(krb_context, principal);
535d341
+		krb5_cc_close(krb_context, ccache);
535d341
+		krb5_free_unparsed_name(krb_context, name);
535d341
+		return 0;
535d341
+	}
535d341
+	krb5_free_unparsed_name(krb_context, name);
535d341
+
535d341
+	/* Name matches, so lets get on with it! */
535d341
+
535d341
+	if ((problem = krb5_cc_initialize(krb_context, ccache, principal))) {
535d341
+		logit("krb5_cc_initialize(): %.100s",
535d341
+		    krb5_get_err_text(krb_context, problem));
535d341
+		krb5_free_principal(krb_context, principal);
535d341
+		krb5_cc_close(krb_context, ccache);
535d341
+		return 0;
535d341
+	}
535d341
+
535d341
+	krb5_free_principal(krb_context, principal);
535d341
+
535d341
+	if ((maj_status = gss_krb5_copy_ccache(&min_status, client->creds,
535d341
+	    ccache))) {
535d341
+		logit("gss_krb5_copy_ccache() failed. Sorry!");
535d341
+		krb5_cc_close(krb_context, ccache);
535d341
+		return 0;
535d341
+	}
535d341
+
535d341
+	return 1;
535d341
+}
535d341
+
535d341
 ssh_gssapi_mech gssapi_kerberos_mech = {
535d341
 	"toWM5Slw5Ew8Mqkay+al2g==",
535d341
 	"Kerberos",
bbf61da
@@ -203,7 +282,8 @@ ssh_gssapi_mech gssapi_kerberos_mech = {
535d341
 	NULL,
535d341
 	&ssh_gssapi_krb5_userok,
535d341
 	NULL,
535d341
-	&ssh_gssapi_krb5_storecreds
535d341
+	&ssh_gssapi_krb5_storecreds,
535d341
+	&ssh_gssapi_krb5_updatecreds
535d341
 };
535d341
 
535d341
 #endif /* KRB5 */
5b55d09
diff -up openssh/kex.c.gsskex openssh/kex.c
bbf61da
--- openssh/kex.c.gsskex	2018-08-20 07:57:29.000000000 +0200
bbf61da
+++ openssh/kex.c	2018-08-22 11:47:33.311216457 +0200
13073f8
@@ -54,6 +54,10 @@
132f8f8
 #include "sshbuf.h"
3e1dd6c
 #include "digest.h"
Jan F. Chadima 69dd72f
 
Jan F. Chadima 69dd72f
+#ifdef GSSAPI
Jan F. Chadima 69dd72f
+#include "ssh-gss.h"
Jan F. Chadima 69dd72f
+#endif
Jan F. Chadima 69dd72f
+
5b55d09
 /* prototype */
5b55d09
 static int kex_choose_conf(struct ssh *);
5b55d09
 static int kex_input_newkeys(int, u_int32_t, struct ssh *);
5b55d09
@@ -103,6 +107,11 @@ static const struct kexalg kexalgs[] = {
3e1dd6c
 	{ KEX_CURVE25519_SHA256, KEX_C25519_SHA256, 0, SSH_DIGEST_SHA256 },
6cf9b8e
 	{ KEX_CURVE25519_SHA256_OLD, KEX_C25519_SHA256, 0, SSH_DIGEST_SHA256 },
132f8f8
 #endif /* HAVE_EVP_SHA256 || !WITH_OPENSSL */
3834483
+#ifdef GSSAPI
3e1dd6c
+	{ KEX_GSS_GEX_SHA1_ID, KEX_GSS_GEX_SHA1, 0, SSH_DIGEST_SHA1 },
3e1dd6c
+	{ KEX_GSS_GRP1_SHA1_ID, KEX_GSS_GRP1_SHA1, 0, SSH_DIGEST_SHA1 },
3e1dd6c
+	{ KEX_GSS_GRP14_SHA1_ID, KEX_GSS_GRP14_SHA1, 0, SSH_DIGEST_SHA1 },
3834483
+#endif
3e1dd6c
 	{ NULL, -1, -1, -1},
84822b5
 };
84822b5
 
5b55d09
@@ -136,6 +145,12 @@ kex_alg_by_name(const char *name)
3834483
 	for (k = kexalgs; k->name != NULL; k++) {
3834483
 		if (strcmp(k->name, name) == 0)
3834483
 			return k;
3834483
+#ifdef GSSAPI
3834483
+		if (strncmp(name, "gss-", 4) == 0) {
3834483
+			if (strncmp(k->name, name, strlen(k->name)) == 0)
3834483
+				return k;
3834483
+		}
3834483
+#endif
3834483
 	}
3834483
 	return NULL;
3834483
 }
5b55d09
diff -up openssh/kexgssc.c.gsskex openssh/kexgssc.c
bbf61da
--- openssh/kexgssc.c.gsskex	2018-08-22 11:47:33.311216457 +0200
bbf61da
+++ openssh/kexgssc.c	2018-08-22 11:47:33.311216457 +0200
132f8f8
@@ -0,0 +1,338 @@
Jan F. Chadima 69dd72f
+/*
Jan F. Chadima 69dd72f
+ * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved.
Jan F. Chadima 69dd72f
+ *
Jan F. Chadima 69dd72f
+ * Redistribution and use in source and binary forms, with or without
Jan F. Chadima 69dd72f
+ * modification, are permitted provided that the following conditions
Jan F. Chadima 69dd72f
+ * are met:
Jan F. Chadima 69dd72f
+ * 1. Redistributions of source code must retain the above copyright
Jan F. Chadima 69dd72f
+ *    notice, this list of conditions and the following disclaimer.
Jan F. Chadima 69dd72f
+ * 2. Redistributions in binary form must reproduce the above copyright
Jan F. Chadima 69dd72f
+ *    notice, this list of conditions and the following disclaimer in the
Jan F. Chadima 69dd72f
+ *    documentation and/or other materials provided with the distribution.
Jan F. Chadima 69dd72f
+ *
Jan F. Chadima 69dd72f
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
Jan F. Chadima 69dd72f
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
Jan F. Chadima 69dd72f
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
Jan F. Chadima 69dd72f
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
Jan F. Chadima 69dd72f
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
Jan F. Chadima 69dd72f
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
Jan F. Chadima 69dd72f
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
Jan F. Chadima 69dd72f
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
Jan F. Chadima 69dd72f
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
Jan F. Chadima 69dd72f
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Jan F. Chadima 69dd72f
+ */
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+#include "includes.h"
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+#ifdef GSSAPI
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+#include "includes.h"
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+#include <openssl/crypto.h>
Jan F. Chadima 69dd72f
+#include <openssl/bn.h>
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+#include <string.h>
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+#include "xmalloc.h"
bbf61da
+#include "sshbuf.h"
Jan F. Chadima 69dd72f
+#include "ssh2.h"
bbf61da
+#include "sshkey.h"
Jan F. Chadima 69dd72f
+#include "cipher.h"
Jan F. Chadima 69dd72f
+#include "kex.h"
Jan F. Chadima 69dd72f
+#include "log.h"
Jan F. Chadima 69dd72f
+#include "packet.h"
Jan F. Chadima 69dd72f
+#include "dh.h"
132f8f8
+#include "digest.h"
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+#include "ssh-gss.h"
Jan F. Chadima 69dd72f
+
132f8f8
+int
132f8f8
+kexgss_client(struct ssh *ssh) {
Jan F. Chadima 69dd72f
+	gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
Jan F. Chadima 69dd72f
+	gss_buffer_desc recv_tok, gssbuf, msg_tok, *token_ptr;
Jan F. Chadima 69dd72f
+	Gssctxt *ctxt;
Jan F. Chadima 69dd72f
+	OM_uint32 maj_status, min_status, ret_flags;
132f8f8
+	u_int klen, kout, slen = 0, strlen;
Jan F. Chadima 69dd72f
+	DH *dh; 
Jan F. Chadima 69dd72f
+	BIGNUM *dh_server_pub = NULL;
Jan F. Chadima 69dd72f
+	BIGNUM *shared_secret = NULL;
Jan F. Chadima 69dd72f
+	BIGNUM *p = NULL;
Jan F. Chadima 69dd72f
+	BIGNUM *g = NULL;	
132f8f8
+	u_char *kbuf;
Jan F. Chadima 69dd72f
+	u_char *serverhostkey = NULL;
Jan F. Chadima 69dd72f
+	u_char *empty = "";
Jan F. Chadima 69dd72f
+	char *msg;
Jan F. Chadima 69dd72f
+	char *lang;
Jan F. Chadima 69dd72f
+	int type = 0;
Jan F. Chadima 69dd72f
+	int first = 1;
Jan F. Chadima 69dd72f
+	int nbits = 0, min = DH_GRP_MIN, max = DH_GRP_MAX;
132f8f8
+	u_char hash[SSH_DIGEST_MAX_LENGTH];
132f8f8
+	size_t hashlen;
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	/* Initialise our GSSAPI world */	
Jan F. Chadima 69dd72f
+	ssh_gssapi_build_ctx(&ctxt);
132f8f8
+	if (ssh_gssapi_id_kex(ctxt, ssh->kex->name, ssh->kex->kex_type) 
Jan F. Chadima 69dd72f
+	    == GSS_C_NO_OID)
Jan F. Chadima 69dd72f
+		fatal("Couldn't identify host exchange");
Jan F. Chadima 69dd72f
+
132f8f8
+	if (ssh_gssapi_import_name(ctxt, ssh->kex->gss_host))
Jan F. Chadima 69dd72f
+		fatal("Couldn't import hostname");
Jan F. Chadima 69dd72f
+
132f8f8
+	if (ssh->kex->gss_client && 
132f8f8
+	    ssh_gssapi_client_identity(ctxt, ssh->kex->gss_client))
Jan F. Chadima 69dd72f
+		fatal("Couldn't acquire client credentials");
Jan F. Chadima 69dd72f
+
132f8f8
+	switch (ssh->kex->kex_type) {
Jan F. Chadima 69dd72f
+	case KEX_GSS_GRP1_SHA1:
Jan F. Chadima 69dd72f
+		dh = dh_new_group1();
Jan F. Chadima 69dd72f
+		break;
Jan F. Chadima 69dd72f
+	case KEX_GSS_GRP14_SHA1:
Jan F. Chadima 69dd72f
+		dh = dh_new_group14();
Jan F. Chadima 69dd72f
+		break;
Jan F. Chadima 69dd72f
+	case KEX_GSS_GEX_SHA1:
Jan F. Chadima 69dd72f
+		debug("Doing group exchange\n");
132f8f8
+		nbits = dh_estimate(ssh->kex->we_need * 8);
Jan F. Chadima 69dd72f
+		packet_start(SSH2_MSG_KEXGSS_GROUPREQ);
Jan F. Chadima 69dd72f
+		packet_put_int(min);
Jan F. Chadima 69dd72f
+		packet_put_int(nbits);
Jan F. Chadima 69dd72f
+		packet_put_int(max);
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+		packet_send();
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+		packet_read_expect(SSH2_MSG_KEXGSS_GROUP);
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+		if ((p = BN_new()) == NULL)
Jan F. Chadima 69dd72f
+			fatal("BN_new() failed");
Jan F. Chadima 69dd72f
+		packet_get_bignum2(p);
Jan F. Chadima 69dd72f
+		if ((g = BN_new()) == NULL)
Jan F. Chadima 69dd72f
+			fatal("BN_new() failed");
Jan F. Chadima 69dd72f
+		packet_get_bignum2(g);
Jan F. Chadima 69dd72f
+		packet_check_eom();
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+		if (BN_num_bits(p) < min || BN_num_bits(p) > max)
Jan F. Chadima 69dd72f
+			fatal("GSSGRP_GEX group out of range: %d !< %d !< %d",
Jan F. Chadima 69dd72f
+			    min, BN_num_bits(p), max);
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+		dh = dh_new_group(g, p);
Jan F. Chadima 69dd72f
+		break;
Jan F. Chadima 69dd72f
+	default:
132f8f8
+		fatal("%s: Unexpected KEX type %d", __func__, ssh->kex->kex_type);
Jan F. Chadima 69dd72f
+	}
Jan F. Chadima 69dd72f
+	
Jan F. Chadima 69dd72f
+	/* Step 1 - e is dh->pub_key */
132f8f8
+	dh_gen_key(dh, ssh->kex->we_need * 8);
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	/* This is f, we initialise it now to make life easier */
Jan F. Chadima 69dd72f
+	dh_server_pub = BN_new();
Jan F. Chadima 69dd72f
+	if (dh_server_pub == NULL)
Jan F. Chadima 69dd72f
+		fatal("dh_server_pub == NULL");
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	token_ptr = GSS_C_NO_BUFFER;
Jan F. Chadima 69dd72f
+			 
Jan F. Chadima 69dd72f
+	do {
Jan F. Chadima 69dd72f
+		debug("Calling gss_init_sec_context");
Jan F. Chadima 69dd72f
+		
Jan F. Chadima 69dd72f
+		maj_status = ssh_gssapi_init_ctx(ctxt,
132f8f8
+		    ssh->kex->gss_deleg_creds, token_ptr, &send_tok,
Jan F. Chadima 69dd72f
+		    &ret_flags);
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+		if (GSS_ERROR(maj_status)) {
Jan F. Chadima 69dd72f
+			if (send_tok.length != 0) {
Jan F. Chadima 69dd72f
+				packet_start(SSH2_MSG_KEXGSS_CONTINUE);
Jan F. Chadima 69dd72f
+				packet_put_string(send_tok.value,
Jan F. Chadima 69dd72f
+				    send_tok.length);
Jan F. Chadima 69dd72f
+			}
Jan F. Chadima 69dd72f
+			fatal("gss_init_context failed");
Jan F. Chadima 69dd72f
+		}
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+		/* If we've got an old receive buffer get rid of it */
Jan F. Chadima 69dd72f
+		if (token_ptr != GSS_C_NO_BUFFER)
84822b5
+			free(recv_tok.value);
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+		if (maj_status == GSS_S_COMPLETE) {
Jan F. Chadima 69dd72f
+			/* If mutual state flag is not true, kex fails */
Jan F. Chadima 69dd72f
+			if (!(ret_flags & GSS_C_MUTUAL_FLAG))
Jan F. Chadima 69dd72f
+				fatal("Mutual authentication failed");
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+			/* If integ avail flag is not true kex fails */
Jan F. Chadima 69dd72f
+			if (!(ret_flags & GSS_C_INTEG_FLAG))
Jan F. Chadima 69dd72f
+				fatal("Integrity check failed");
Jan F. Chadima 69dd72f
+		}
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+		/* 
Jan F. Chadima 69dd72f
+		 * If we have data to send, then the last message that we
Jan F. Chadima 69dd72f
+		 * received cannot have been a 'complete'. 
Jan F. Chadima 69dd72f
+		 */
Jan F. Chadima 69dd72f
+		if (send_tok.length != 0) {
Jan F. Chadima 69dd72f
+			if (first) {
Jan F. Chadima 69dd72f
+				packet_start(SSH2_MSG_KEXGSS_INIT);
Jan F. Chadima 69dd72f
+				packet_put_string(send_tok.value,
Jan F. Chadima 69dd72f
+				    send_tok.length);
Jan F. Chadima 69dd72f
+				packet_put_bignum2(dh->pub_key);
Jan F. Chadima 69dd72f
+				first = 0;
Jan F. Chadima 69dd72f
+			} else {
Jan F. Chadima 69dd72f
+				packet_start(SSH2_MSG_KEXGSS_CONTINUE);
Jan F. Chadima 69dd72f
+				packet_put_string(send_tok.value,
Jan F. Chadima 69dd72f
+				    send_tok.length);
Jan F. Chadima 69dd72f
+			}
Jan F. Chadima 69dd72f
+			packet_send();
Jan F. Chadima 69dd72f
+			gss_release_buffer(&min_status, &send_tok);
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+			/* If we've sent them data, they should reply */
Jan F. Chadima 69dd72f
+			do {	
Jan F. Chadima 69dd72f
+				type = packet_read();
Jan F. Chadima 69dd72f
+				if (type == SSH2_MSG_KEXGSS_HOSTKEY) {
Jan F. Chadima 69dd72f
+					debug("Received KEXGSS_HOSTKEY");
Jan F. Chadima 69dd72f
+					if (serverhostkey)
Jan F. Chadima 69dd72f
+						fatal("Server host key received more than once");
Jan F. Chadima 69dd72f
+					serverhostkey = 
Jan F. Chadima 69dd72f
+					    packet_get_string(&slen);
Jan F. Chadima 69dd72f
+				}
Jan F. Chadima 69dd72f
+			} while (type == SSH2_MSG_KEXGSS_HOSTKEY);
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+			switch (type) {
Jan F. Chadima 69dd72f
+			case SSH2_MSG_KEXGSS_CONTINUE:
Jan F. Chadima 69dd72f
+				debug("Received GSSAPI_CONTINUE");
Jan F. Chadima 69dd72f
+				if (maj_status == GSS_S_COMPLETE) 
Jan F. Chadima 69dd72f
+					fatal("GSSAPI Continue received from server when complete");
Jan F. Chadima 69dd72f
+				recv_tok.value = packet_get_string(&strlen);
Jan F. Chadima 69dd72f
+				recv_tok.length = strlen; 
Jan F. Chadima 69dd72f
+				break;
Jan F. Chadima 69dd72f
+			case SSH2_MSG_KEXGSS_COMPLETE:
Jan F. Chadima 69dd72f
+				debug("Received GSSAPI_COMPLETE");
Jan F. Chadima 69dd72f
+				packet_get_bignum2(dh_server_pub);
Jan F. Chadima 69dd72f
+				msg_tok.value =  packet_get_string(&strlen);
Jan F. Chadima 69dd72f
+				msg_tok.length = strlen; 
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+				/* Is there a token included? */
Jan F. Chadima 69dd72f
+				if (packet_get_char()) {
Jan F. Chadima 69dd72f
+					recv_tok.value=
Jan F. Chadima 69dd72f
+					    packet_get_string(&strlen);
Jan F. Chadima 69dd72f
+					recv_tok.length = strlen;
Jan F. Chadima 69dd72f
+					/* If we're already complete - protocol error */
Jan F. Chadima 69dd72f
+					if (maj_status == GSS_S_COMPLETE)
Jan F. Chadima 69dd72f
+						packet_disconnect("Protocol error: received token when complete");
Jan F. Chadima 69dd72f
+					} else {
Jan F. Chadima 69dd72f
+						/* No token included */
Jan F. Chadima 69dd72f
+						if (maj_status != GSS_S_COMPLETE)
Jan F. Chadima 69dd72f
+							packet_disconnect("Protocol error: did not receive final token");
Jan F. Chadima 69dd72f
+				}
Jan F. Chadima 69dd72f
+				break;
Jan F. Chadima 69dd72f
+			case SSH2_MSG_KEXGSS_ERROR:
Jan F. Chadima 69dd72f
+				debug("Received Error");
Jan F. Chadima 69dd72f
+				maj_status = packet_get_int();
Jan F. Chadima 69dd72f
+				min_status = packet_get_int();
Jan F. Chadima 69dd72f
+				msg = packet_get_string(NULL);
Jan F. Chadima 69dd72f
+				lang = packet_get_string(NULL);
Jan F. Chadima 69dd72f
+				fatal("GSSAPI Error: \n%.400s",msg);
Jan F. Chadima 69dd72f
+			default:
Jan F. Chadima 69dd72f
+				packet_disconnect("Protocol error: didn't expect packet type %d",
Jan F. Chadima 69dd72f
+		    		type);
Jan F. Chadima 69dd72f
+			}
Jan F. Chadima 69dd72f
+			token_ptr = &recv_tok;
Jan F. Chadima 69dd72f
+		} else {
Jan F. Chadima 69dd72f
+			/* No data, and not complete */
Jan F. Chadima 69dd72f
+			if (maj_status != GSS_S_COMPLETE)
Jan F. Chadima 69dd72f
+				fatal("Not complete, and no token output");
Jan F. Chadima 69dd72f
+		}
Jan F. Chadima 69dd72f
+	} while (maj_status & GSS_S_CONTINUE_NEEDED);
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	/* 
Jan F. Chadima 69dd72f
+	 * We _must_ have received a COMPLETE message in reply from the 
Jan F. Chadima 69dd72f
+	 * server, which will have set dh_server_pub and msg_tok 
Jan F. Chadima 69dd72f
+	 */
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	if (type != SSH2_MSG_KEXGSS_COMPLETE)
Jan F. Chadima 69dd72f
+		fatal("Didn't receive a SSH2_MSG_KEXGSS_COMPLETE when I expected it");
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	/* Check f in range [1, p-1] */
Jan F. Chadima 69dd72f
+	if (!dh_pub_is_valid(dh, dh_server_pub))
Jan F. Chadima 69dd72f
+		packet_disconnect("bad server public DH value");
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	/* compute K=f^x mod p */
Jan F. Chadima 69dd72f
+	klen = DH_size(dh);
Jan F. Chadima 69dd72f
+	kbuf = xmalloc(klen);
Jan F. Chadima 69dd72f
+	kout = DH_compute_key(kbuf, dh_server_pub, dh);
Jan F. Chadima 3b545be
+	if ((int)kout < 0)
Jan F. Chadima 69dd72f
+		fatal("DH_compute_key: failed");
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	shared_secret = BN_new();
Jan F. Chadima 69dd72f
+	if (shared_secret == NULL)
Jan F. Chadima 69dd72f
+		fatal("kexgss_client: BN_new failed");
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	if (BN_bin2bn(kbuf, kout, shared_secret) == NULL)
Jan F. Chadima 69dd72f
+		fatal("kexdh_client: BN_bin2bn failed");
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	memset(kbuf, 0, klen);
84822b5
+	free(kbuf);
Jan F. Chadima 69dd72f
+
132f8f8
+	hashlen = sizeof(hash);
132f8f8
+	switch (ssh->kex->kex_type) {
Jan F. Chadima 69dd72f
+	case KEX_GSS_GRP1_SHA1:
Jan F. Chadima 69dd72f
+	case KEX_GSS_GRP14_SHA1:
b487a6d
+		kex_dh_hash(ssh->kex->hash_alg, ssh->kex->client_version_string, 
132f8f8
+		    ssh->kex->server_version_string,
bbf61da
+		    sshbuf_ptr(ssh->kex->my), sshbuf_len(ssh->kex->my),
bbf61da
+		    sshbuf_ptr(ssh->kex->peer), sshbuf_len(ssh->kex->peer),
Jan F. Chadima 69dd72f
+		    (serverhostkey ? serverhostkey : empty), slen,
Jan F. Chadima 69dd72f
+		    dh->pub_key,	/* e */
Jan F. Chadima 69dd72f
+		    dh_server_pub,	/* f */
Jan F. Chadima 69dd72f
+		    shared_secret,	/* K */
132f8f8
+		    hash, &hashlen
Jan F. Chadima 69dd72f
+		);
Jan F. Chadima 69dd72f
+		break;
Jan F. Chadima 69dd72f
+	case KEX_GSS_GEX_SHA1:
Jan F. Chadima 69dd72f
+		kexgex_hash(
132f8f8
+		    ssh->kex->hash_alg,
132f8f8
+		    ssh->kex->client_version_string,
132f8f8
+		    ssh->kex->server_version_string,
bbf61da
+		    sshbuf_ptr(ssh->kex->my), sshbuf_len(ssh->kex->my),
bbf61da
+		    sshbuf_ptr(ssh->kex->peer), sshbuf_len(ssh->kex->peer),
Jan F. Chadima 69dd72f
+		    (serverhostkey ? serverhostkey : empty), slen,
Jan F. Chadima 69dd72f
+ 		    min, nbits, max,
Jan F. Chadima 69dd72f
+		    dh->p, dh->g,
Jan F. Chadima 69dd72f
+		    dh->pub_key,
Jan F. Chadima 69dd72f
+		    dh_server_pub,
Jan F. Chadima 69dd72f
+		    shared_secret,
132f8f8
+		    hash, &hashlen
Jan F. Chadima 69dd72f
+		);
Jan F. Chadima 69dd72f
+		break;
Jan F. Chadima 69dd72f
+	default:
132f8f8
+		fatal("%s: Unexpected KEX type %d", __func__, ssh->kex->kex_type);
Jan F. Chadima 69dd72f
+	}
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	gssbuf.value = hash;
Jan F. Chadima 69dd72f
+	gssbuf.length = hashlen;
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	/* Verify that the hash matches the MIC we just got. */
Jan F. Chadima 69dd72f
+	if (GSS_ERROR(ssh_gssapi_checkmic(ctxt, &gssbuf, &msg_tok)))
Jan F. Chadima 69dd72f
+		packet_disconnect("Hash's MIC didn't verify");
Jan F. Chadima 69dd72f
+
84822b5
+	free(msg_tok.value);
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	DH_free(dh);
Jan F. Chadima 69dd72f
+	if (serverhostkey)
84822b5
+		free(serverhostkey);
Jan F. Chadima 69dd72f
+	BN_clear_free(dh_server_pub);
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	/* save session id */
132f8f8
+	if (ssh->kex->session_id == NULL) {
132f8f8
+		ssh->kex->session_id_len = hashlen;
132f8f8
+		ssh->kex->session_id = xmalloc(ssh->kex->session_id_len);
132f8f8
+		memcpy(ssh->kex->session_id, hash, ssh->kex->session_id_len);
Jan F. Chadima 69dd72f
+	}
Jan F. Chadima 69dd72f
+
132f8f8
+	if (ssh->kex->gss_deleg_creds)
Jan F. Chadima 69dd72f
+		ssh_gssapi_credentials_updated(ctxt);
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	if (gss_kex_context == NULL)
Jan F. Chadima 69dd72f
+		gss_kex_context = ctxt;
Jan F. Chadima 69dd72f
+	else
Jan F. Chadima 69dd72f
+		ssh_gssapi_delete_ctx(&ctxt);
Jan F. Chadima 69dd72f
+
132f8f8
+	kex_derive_keys_bn(ssh, hash, hashlen, shared_secret);
Jan F. Chadima 69dd72f
+	BN_clear_free(shared_secret);
132f8f8
+	return kex_send_newkeys(ssh);
Jan F. Chadima 69dd72f
+}
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+#endif /* GSSAPI */
5b55d09
diff -up openssh/kexgsss.c.gsskex openssh/kexgsss.c
bbf61da
--- openssh/kexgsss.c.gsskex	2018-08-22 11:47:33.311216457 +0200
bbf61da
+++ openssh/kexgsss.c	2018-08-22 11:47:33.311216457 +0200
b487a6d
@@ -0,0 +1,297 @@
Jan F. Chadima 69dd72f
+/*
Jan F. Chadima 69dd72f
+ * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved.
Jan F. Chadima 69dd72f
+ *
Jan F. Chadima 69dd72f
+ * Redistribution and use in source and binary forms, with or without
Jan F. Chadima 69dd72f
+ * modification, are permitted provided that the following conditions
Jan F. Chadima 69dd72f
+ * are met:
Jan F. Chadima 69dd72f
+ * 1. Redistributions of source code must retain the above copyright
Jan F. Chadima 69dd72f
+ *    notice, this list of conditions and the following disclaimer.
Jan F. Chadima 69dd72f
+ * 2. Redistributions in binary form must reproduce the above copyright
Jan F. Chadima 69dd72f
+ *    notice, this list of conditions and the following disclaimer in the
Jan F. Chadima 69dd72f
+ *    documentation and/or other materials provided with the distribution.
Jan F. Chadima 69dd72f
+ *
Jan F. Chadima 69dd72f
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
Jan F. Chadima 69dd72f
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
Jan F. Chadima 69dd72f
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
Jan F. Chadima 69dd72f
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
Jan F. Chadima 69dd72f
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
Jan F. Chadima 69dd72f
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
Jan F. Chadima 69dd72f
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
Jan F. Chadima 69dd72f
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
Jan F. Chadima 69dd72f
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
Jan F. Chadima 69dd72f
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Jan F. Chadima 69dd72f
+ */
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+#include "includes.h"
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+#ifdef GSSAPI
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+#include <string.h>
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+#include <openssl/crypto.h>
Jan F. Chadima 69dd72f
+#include <openssl/bn.h>
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+#include "xmalloc.h"
bbf61da
+#include "sshbuf.h"
Jan F. Chadima 69dd72f
+#include "ssh2.h"
bbf61da
+#include "sshkey.h"
Jan F. Chadima 69dd72f
+#include "cipher.h"
Jan F. Chadima 69dd72f
+#include "kex.h"
Jan F. Chadima 69dd72f
+#include "log.h"
Jan F. Chadima 69dd72f
+#include "packet.h"
Jan F. Chadima 69dd72f
+#include "dh.h"
Jan F. Chadima 69dd72f
+#include "ssh-gss.h"
Jan F. Chadima 69dd72f
+#include "monitor_wrap.h"
1900351
+#include "misc.h"      /* servconf.h needs misc.h for struct ForwardOptions */
Jan F. Chadima 69dd72f
+#include "servconf.h"
580f986
+#include "ssh-gss.h"
132f8f8
+#include "digest.h"
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+extern ServerOptions options;
Jan F. Chadima 69dd72f
+
132f8f8
+int
132f8f8
+kexgss_server(struct ssh *ssh)
Jan F. Chadima 69dd72f
+{
Jan F. Chadima 69dd72f
+	OM_uint32 maj_status, min_status;
Jan F. Chadima 69dd72f
+	
Jan F. Chadima 69dd72f
+	/* 
Jan F. Chadima 69dd72f
+	 * Some GSSAPI implementations use the input value of ret_flags (an
Jan F. Chadima 69dd72f
+ 	 * output variable) as a means of triggering mechanism specific 
Jan F. Chadima 69dd72f
+ 	 * features. Initializing it to zero avoids inadvertently 
Jan F. Chadima 69dd72f
+ 	 * activating this non-standard behaviour.
Jan F. Chadima 69dd72f
+	 */
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	OM_uint32 ret_flags = 0;
Jan F. Chadima 69dd72f
+	gss_buffer_desc gssbuf, recv_tok, msg_tok;
Jan F. Chadima 69dd72f
+	gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
Jan F. Chadima 69dd72f
+	Gssctxt *ctxt = NULL;
132f8f8
+	u_int slen, klen, kout;
132f8f8
+	u_char *kbuf;
Jan F. Chadima 69dd72f
+	DH *dh;
Jan F. Chadima 69dd72f
+	int min = -1, max = -1, nbits = -1;
5878ebb
+	int cmin = -1, cmax = -1; /* client proposal */
Jan F. Chadima 69dd72f
+	BIGNUM *shared_secret = NULL;
Jan F. Chadima 69dd72f
+	BIGNUM *dh_client_pub = NULL;
Jan F. Chadima 69dd72f
+	int type = 0;
Jan F. Chadima 69dd72f
+	gss_OID oid;
Jan F. Chadima 69dd72f
+	char *mechs;
132f8f8
+	u_char hash[SSH_DIGEST_MAX_LENGTH];
132f8f8
+	size_t hashlen;
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	/* Initialise GSSAPI */
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	/* If we're rekeying, privsep means that some of the private structures
Jan F. Chadima 69dd72f
+	 * in the GSSAPI code are no longer available. This kludges them back
Jan F. Chadima 69dd72f
+	 * into life
Jan F. Chadima 69dd72f
+	 */
Jan F. Chadima 69dd72f
+	if (!ssh_gssapi_oid_table_ok()) 
Jan F. Chadima 69dd72f
+		if ((mechs = ssh_gssapi_server_mechanisms()))
84822b5
+			free(mechs);
Jan F. Chadima 69dd72f
+
132f8f8
+	debug2("%s: Identifying %s", __func__, ssh->kex->name);
132f8f8
+	oid = ssh_gssapi_id_kex(NULL, ssh->kex->name, ssh->kex->kex_type);
Jan F. Chadima 69dd72f
+	if (oid == GSS_C_NO_OID)
Jan F. Chadima 69dd72f
+	   fatal("Unknown gssapi mechanism");
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	debug2("%s: Acquiring credentials", __func__);
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, oid))))
Jan F. Chadima 69dd72f
+		fatal("Unable to acquire credentials for the server");
Jan F. Chadima 69dd72f
+
132f8f8
+	switch (ssh->kex->kex_type) {
Jan F. Chadima 69dd72f
+	case KEX_GSS_GRP1_SHA1:
Jan F. Chadima 69dd72f
+		dh = dh_new_group1();
Jan F. Chadima 69dd72f
+		break;
Jan F. Chadima 69dd72f
+	case KEX_GSS_GRP14_SHA1:
Jan F. Chadima 69dd72f
+		dh = dh_new_group14();
Jan F. Chadima 69dd72f
+		break;
Jan F. Chadima 69dd72f
+	case KEX_GSS_GEX_SHA1:
Jan F. Chadima 69dd72f
+		debug("Doing group exchange");
Jan F. Chadima 69dd72f
+		packet_read_expect(SSH2_MSG_KEXGSS_GROUPREQ);
5878ebb
+		/* store client proposal to provide valid signature */
5878ebb
+		cmin = packet_get_int();
Jan F. Chadima 69dd72f
+		nbits = packet_get_int();
5878ebb
+		cmax = packet_get_int();
5878ebb
+		min = MAX(DH_GRP_MIN, cmin);
5878ebb
+		max = MIN(DH_GRP_MAX, cmax);
Jan F. Chadima 69dd72f
+		packet_check_eom();
Jan F. Chadima 69dd72f
+		if (max < min || nbits < min || max < nbits)
Jan F. Chadima 69dd72f
+			fatal("GSS_GEX, bad parameters: %d !< %d !< %d",
Jan F. Chadima 69dd72f
+			    min, nbits, max);
Jan F. Chadima 69dd72f
+		dh = PRIVSEP(choose_dh(min, nbits, max));
Jan F. Chadima 69dd72f
+		if (dh == NULL)
Jan F. Chadima 69dd72f
+			packet_disconnect("Protocol error: no matching group found");
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+		packet_start(SSH2_MSG_KEXGSS_GROUP);
Jan F. Chadima 69dd72f
+		packet_put_bignum2(dh->p);
Jan F. Chadima 69dd72f
+		packet_put_bignum2(dh->g);
Jan F. Chadima 69dd72f
+		packet_send();
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+		packet_write_wait();
Jan F. Chadima 69dd72f
+		break;
Jan F. Chadima 69dd72f
+	default:
132f8f8
+		fatal("%s: Unexpected KEX type %d", __func__, ssh->kex->kex_type);
Jan F. Chadima 69dd72f
+	}
Jan F. Chadima 69dd72f
+
132f8f8
+	dh_gen_key(dh, ssh->kex->we_need * 8);
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	do {
Jan F. Chadima 69dd72f
+		debug("Wait SSH2_MSG_GSSAPI_INIT");
Jan F. Chadima 69dd72f
+		type = packet_read();
Jan F. Chadima 69dd72f
+		switch(type) {
Jan F. Chadima 69dd72f
+		case SSH2_MSG_KEXGSS_INIT:
Jan F. Chadima 69dd72f
+			if (dh_client_pub != NULL) 
Jan F. Chadima 69dd72f
+				fatal("Received KEXGSS_INIT after initialising");
Jan F. Chadima 69dd72f
+			recv_tok.value = packet_get_string(&slen);
Jan F. Chadima 69dd72f
+			recv_tok.length = slen; 
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+			if ((dh_client_pub = BN_new()) == NULL)
Jan F. Chadima 69dd72f
+				fatal("dh_client_pub == NULL");
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+			packet_get_bignum2(dh_client_pub);
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+			/* Send SSH_MSG_KEXGSS_HOSTKEY here, if we want */
Jan F. Chadima 69dd72f
+			break;
Jan F. Chadima 69dd72f
+		case SSH2_MSG_KEXGSS_CONTINUE:
Jan F. Chadima 69dd72f
+			recv_tok.value = packet_get_string(&slen);
Jan F. Chadima 69dd72f
+			recv_tok.length = slen; 
Jan F. Chadima 69dd72f
+			break;
Jan F. Chadima 69dd72f
+		default:
Jan F. Chadima 69dd72f
+			packet_disconnect(
Jan F. Chadima 69dd72f
+			    "Protocol error: didn't expect packet type %d",
Jan F. Chadima 69dd72f
+			    type);
Jan F. Chadima 69dd72f
+		}
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+		maj_status = PRIVSEP(ssh_gssapi_accept_ctx(ctxt, &recv_tok, 
Jan F. Chadima 69dd72f
+		    &send_tok, &ret_flags));
Jan F. Chadima 69dd72f
+
84822b5
+		free(recv_tok.value);
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+		if (maj_status != GSS_S_COMPLETE && send_tok.length == 0)
Jan F. Chadima 69dd72f
+			fatal("Zero length token output when incomplete");
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+		if (dh_client_pub == NULL)
Jan F. Chadima 69dd72f
+			fatal("No client public key");
Jan F. Chadima 69dd72f
+		
Jan F. Chadima 69dd72f
+		if (maj_status & GSS_S_CONTINUE_NEEDED) {
Jan F. Chadima 69dd72f
+			debug("Sending GSSAPI_CONTINUE");
Jan F. Chadima 69dd72f
+			packet_start(SSH2_MSG_KEXGSS_CONTINUE);
Jan F. Chadima 69dd72f
+			packet_put_string(send_tok.value, send_tok.length);
Jan F. Chadima 69dd72f
+			packet_send();
Jan F. Chadima 69dd72f
+			gss_release_buffer(&min_status, &send_tok);
Jan F. Chadima 69dd72f
+		}
Jan F. Chadima 69dd72f
+	} while (maj_status & GSS_S_CONTINUE_NEEDED);
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	if (GSS_ERROR(maj_status)) {
Jan F. Chadima 69dd72f
+		if (send_tok.length > 0) {
Jan F. Chadima 69dd72f
+			packet_start(SSH2_MSG_KEXGSS_CONTINUE);
Jan F. Chadima 69dd72f
+			packet_put_string(send_tok.value, send_tok.length);
Jan F. Chadima 69dd72f
+			packet_send();
Jan F. Chadima 69dd72f
+		}
Jan F. Chadima 69dd72f
+		fatal("accept_ctx died");
Jan F. Chadima 69dd72f
+	}
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	if (!(ret_flags & GSS_C_MUTUAL_FLAG))
Jan F. Chadima 69dd72f
+		fatal("Mutual Authentication flag wasn't set");
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	if (!(ret_flags & GSS_C_INTEG_FLAG))
Jan F. Chadima 69dd72f
+		fatal("Integrity flag wasn't set");
Jan F. Chadima 69dd72f
+	
Jan F. Chadima 69dd72f
+	if (!dh_pub_is_valid(dh, dh_client_pub))
Jan F. Chadima 69dd72f
+		packet_disconnect("bad client public DH value");
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	klen = DH_size(dh);
Jan F. Chadima 69dd72f
+	kbuf = xmalloc(klen); 
Jan F. Chadima 69dd72f
+	kout = DH_compute_key(kbuf, dh_client_pub, dh);
Jan F. Chadima 3b545be
+	if ((int)kout < 0)
Jan F. Chadima 69dd72f
+		fatal("DH_compute_key: failed");
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	shared_secret = BN_new();
Jan F. Chadima 69dd72f
+	if (shared_secret == NULL)
Jan F. Chadima 69dd72f
+		fatal("kexgss_server: BN_new failed");
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	if (BN_bin2bn(kbuf, kout, shared_secret) == NULL)
Jan F. Chadima 69dd72f
+		fatal("kexgss_server: BN_bin2bn failed");
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	memset(kbuf, 0, klen);
84822b5
+	free(kbuf);
Jan F. Chadima 69dd72f
+
132f8f8
+	hashlen = sizeof(hash);
132f8f8
+	switch (ssh->kex->kex_type) {
Jan F. Chadima 69dd72f
+	case KEX_GSS_GRP1_SHA1:
Jan F. Chadima 69dd72f
+	case KEX_GSS_GRP14_SHA1:
b487a6d
+		kex_dh_hash(ssh->kex->hash_alg,
132f8f8
+		    ssh->kex->client_version_string, ssh->kex->server_version_string,
bbf61da
+		    sshbuf_ptr(ssh->kex->peer), sshbuf_len(ssh->kex->peer),
bbf61da
+		    sshbuf_ptr(ssh->kex->my), sshbuf_len(ssh->kex->my),
Jan F. Chadima 69dd72f
+		    NULL, 0, /* Change this if we start sending host keys */
Jan F. Chadima 69dd72f
+		    dh_client_pub, dh->pub_key, shared_secret,
132f8f8
+		    hash, &hashlen
Jan F. Chadima 69dd72f
+		);
Jan F. Chadima 69dd72f
+		break;
Jan F. Chadima 69dd72f
+	case KEX_GSS_GEX_SHA1:
Jan F. Chadima 69dd72f
+		kexgex_hash(
132f8f8
+		    ssh->kex->hash_alg,
132f8f8
+		    ssh->kex->client_version_string, ssh->kex->server_version_string,
bbf61da
+		    sshbuf_ptr(ssh->kex->peer), sshbuf_len(ssh->kex->peer),
bbf61da
+		    sshbuf_ptr(ssh->kex->my), sshbuf_len(ssh->kex->my),
Jan F. Chadima 69dd72f
+		    NULL, 0,
5878ebb
+		    cmin, nbits, cmax,
Jan F. Chadima 69dd72f
+		    dh->p, dh->g,
Jan F. Chadima 69dd72f
+		    dh_client_pub,
Jan F. Chadima 69dd72f
+		    dh->pub_key,
Jan F. Chadima 69dd72f
+		    shared_secret,
132f8f8
+		    hash, &hashlen
Jan F. Chadima 69dd72f
+		);
Jan F. Chadima 69dd72f
+		break;
Jan F. Chadima 69dd72f
+	default:
132f8f8
+		fatal("%s: Unexpected KEX type %d", __func__, ssh->kex->kex_type);
Jan F. Chadima 69dd72f
+	}
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	BN_clear_free(dh_client_pub);
Jan F. Chadima 69dd72f
+
132f8f8
+	if (ssh->kex->session_id == NULL) {
132f8f8
+		ssh->kex->session_id_len = hashlen;
132f8f8
+		ssh->kex->session_id = xmalloc(ssh->kex->session_id_len);
132f8f8
+		memcpy(ssh->kex->session_id, hash, ssh->kex->session_id_len);
Jan F. Chadima 69dd72f
+	}
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	gssbuf.value = hash;
Jan F. Chadima 69dd72f
+	gssbuf.length = hashlen;
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	if (GSS_ERROR(PRIVSEP(ssh_gssapi_sign(ctxt,&gssbuf,&msg_tok))))
Jan F. Chadima 69dd72f
+		fatal("Couldn't get MIC");
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	packet_start(SSH2_MSG_KEXGSS_COMPLETE);
Jan F. Chadima 69dd72f
+	packet_put_bignum2(dh->pub_key);
Jan F. Chadima 69dd72f
+	packet_put_string(msg_tok.value,msg_tok.length);
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	if (send_tok.length != 0) {
Jan F. Chadima 69dd72f
+		packet_put_char(1); /* true */
Jan F. Chadima 69dd72f
+		packet_put_string(send_tok.value, send_tok.length);
Jan F. Chadima 69dd72f
+	} else {
Jan F. Chadima 69dd72f
+		packet_put_char(0); /* false */
Jan F. Chadima 69dd72f
+	}
Jan F. Chadima 69dd72f
+	packet_send();
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	gss_release_buffer(&min_status, &send_tok);
Jan F. Chadima 69dd72f
+	gss_release_buffer(&min_status, &msg_tok);
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	if (gss_kex_context == NULL)
Jan F. Chadima 69dd72f
+		gss_kex_context = ctxt;
Jan F. Chadima 69dd72f
+	else 
Jan F. Chadima 69dd72f
+		ssh_gssapi_delete_ctx(&ctxt);
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	DH_free(dh);
Jan F. Chadima 69dd72f
+
132f8f8
+	kex_derive_keys_bn(ssh, hash, hashlen, shared_secret);
Jan F. Chadima 69dd72f
+	BN_clear_free(shared_secret);
132f8f8
+	kex_send_newkeys(ssh);
Jan F. Chadima 69dd72f
+
d9e6186
+	/* If this was a rekey, then save out any delegated credentials we
d9e6186
+	 * just exchanged.  */
d9e6186
+	if (options.gss_store_rekey)
d9e6186
+		ssh_gssapi_rekey_creds();
132f8f8
+	return 0;
d9e6186
+}
d9e6186
+#endif /* GSSAPI */
5b55d09
diff -up openssh/kex.h.gsskex openssh/kex.h
bbf61da
--- openssh/kex.h.gsskex	2018-08-20 07:57:29.000000000 +0200
bbf61da
+++ openssh/kex.h	2018-08-22 11:47:33.311216457 +0200
bbf61da
@@ -100,6 +100,11 @@ enum kex_exchange {
535d341
 	KEX_DH_GEX_SHA256,
535d341
 	KEX_ECDH_SHA2,
535d341
 	KEX_C25519_SHA256,
535d341
+#ifdef GSSAPI
535d341
+	KEX_GSS_GRP1_SHA1,
535d341
+	KEX_GSS_GRP14_SHA1,
535d341
+	KEX_GSS_GEX_SHA1,
535d341
+#endif
535d341
 	KEX_MAX
535d341
 };
535d341
 
bbf61da
@@ -148,6 +153,12 @@ struct kex {
535d341
 	u_int	flags;
535d341
 	int	hash_alg;
535d341
 	int	ec_nid;
535d341
+#ifdef GSSAPI
535d341
+	int	gss_deleg_creds;
535d341
+	int	gss_trust_dns;
535d341
+	char    *gss_host;
535d341
+	char	*gss_client;
535d341
+#endif
535d341
 	char	*client_version_string;
535d341
 	char	*server_version_string;
3f55133
 	char	*failed_choice;
bbf61da
@@ -197,6 +208,10 @@ int	 kexecdh_client(struct ssh *);
535d341
 int	 kexecdh_server(struct ssh *);
535d341
 int	 kexc25519_client(struct ssh *);
535d341
 int	 kexc25519_server(struct ssh *);
535d341
+#ifdef GSSAPI
535d341
+int	 kexgss_client(struct ssh *);
535d341
+int	 kexgss_server(struct ssh *);
535d341
+#endif
535d341
 
5878ebb
 int	 kex_dh_hash(int, const char *, const char *,
535d341
     const u_char *, size_t, const u_char *, size_t, const u_char *, size_t,
5b55d09
diff -up openssh/Makefile.in.gsskex openssh/Makefile.in
bbf61da
--- openssh/Makefile.in.gsskex	2018-08-22 11:47:33.312216465 +0200
bbf61da
+++ openssh/Makefile.in	2018-08-22 13:19:54.955928277 +0200
bbf61da
@@ -100,6 +100,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \
5b55d09
 	readpass.o ttymodes.o xmalloc.o addrmatch.o \
bbf61da
 	atomicio.o dispatch.o mac.o uuencode.o misc.o utf8.o \
535d341
 	monitor_fdpass.o rijndael.o ssh-dss.o ssh-ecdsa.o ssh-rsa.o dh.o \
535d341
+	kexgssc.o \
535d341
 	msg.o progressmeter.o dns.o entropy.o gss-genr.o umac.o umac128.o \
535d341
 	ssh-pkcs11.o smult_curve25519_ref.o \
535d341
 	poly1305.o chacha.o cipher-chachapoly.o \
bbf61da
@@ -121,7 +122,7 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passw
bbf61da
 	auth-bsdauth.o auth2-hostbased.o auth2-kbdint.o \
535d341
 	auth2-none.o auth2-passwd.o auth2-pubkey.o \
6cf9b8e
 	monitor.o monitor_wrap.o auth-krb5.o \
535d341
-	auth2-gss.o gss-serv.o gss-serv-krb5.o \
6cf9b8e
+	auth2-gss.o gss-serv.o gss-serv-krb5.o kexgsss.o \
535d341
 	loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \
535d341
 	sftp-server.o sftp-common.o \
13073f8
 	sandbox-null.o sandbox-rlimit.o sandbox-systrace.o sandbox-darwin.o \
5b55d09
diff -up openssh/monitor.c.gsskex openssh/monitor.c
bbf61da
--- openssh/monitor.c.gsskex	2018-08-22 11:47:33.263216069 +0200
bbf61da
+++ openssh/monitor.c	2018-08-22 13:22:19.589095240 +0200
bbf61da
@@ -146,6 +146,8 @@ int mm_answer_gss_setup_ctx(int, struct
bbf61da
 int mm_answer_gss_accept_ctx(int, struct sshbuf *);
bbf61da
 int mm_answer_gss_userok(int, struct sshbuf *);
bbf61da
 int mm_answer_gss_checkmic(int, struct sshbuf *);
bbf61da
+int mm_answer_gss_sign(int, struct sshbuf *);
bbf61da
+int mm_answer_gss_updatecreds(int, struct sshbuf *);
Jan F. Chadima 69dd72f
 #endif
Jan F. Chadima 69dd72f
 
Jan F. Chadima 69dd72f
 #ifdef SSH_AUDIT_EVENTS
bbf61da
@@ -219,11 +221,18 @@ struct mon_table mon_dispatch_proto20[]
6cf9b8e
     {MONITOR_REQ_GSSSTEP, 0, mm_answer_gss_accept_ctx},
6cf9b8e
     {MONITOR_REQ_GSSUSEROK, MON_ONCE|MON_AUTHDECIDE, mm_answer_gss_userok},
6cf9b8e
     {MONITOR_REQ_GSSCHECKMIC, MON_ONCE, mm_answer_gss_checkmic},
57666dc
+    {MONITOR_REQ_GSSSIGN, MON_ONCE, mm_answer_gss_sign},
57666dc
 #endif
57666dc
     {0, 0, NULL}
Jan F. Chadima 69dd72f
 };
Jan F. Chadima 69dd72f
 
Jan F. Chadima 69dd72f
 struct mon_table mon_dispatch_postauth20[] = {
Jan F. Chadima 69dd72f
+#ifdef GSSAPI
Jan F. Chadima 69dd72f
+    {MONITOR_REQ_GSSSETUP, 0, mm_answer_gss_setup_ctx},
Jan F. Chadima 69dd72f
+    {MONITOR_REQ_GSSSTEP, 0, mm_answer_gss_accept_ctx},
Jan F. Chadima 69dd72f
+    {MONITOR_REQ_GSSSIGN, 0, mm_answer_gss_sign},
Jan F. Chadima 69dd72f
+    {MONITOR_REQ_GSSUPCREDS, 0, mm_answer_gss_updatecreds},
Jan F. Chadima 69dd72f
+#endif
1900351
 #ifdef WITH_OPENSSL
Jan F. Chadima 69dd72f
     {MONITOR_REQ_MODULI, 0, mm_answer_moduli},
1900351
 #endif
bbf61da
@@ -293,6 +302,10 @@ monitor_child_preauth(Authctxt *_authctx
6cf9b8e
 	/* Permit requests for moduli and signatures */
6cf9b8e
 	monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1);
6cf9b8e
 	monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1);
Jan F. Chadima 69dd72f
+#ifdef GSSAPI
6cf9b8e
+	/* and for the GSSAPI key exchange */
6cf9b8e
+	monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1);
Jan F. Chadima 69dd72f
+#endif
5039c7c
 
6cf9b8e
 	/* The first few requests do not require asynchronous access */
6cf9b8e
 	while (!authenticated) {
bbf61da
@@ -405,6 +418,10 @@ monitor_child_postauth(struct monitor *p
6cf9b8e
 	monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1);
6cf9b8e
 	monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1);
6cf9b8e
 	monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1);
Jan F. Chadima 69dd72f
+#ifdef GSSAPI
6cf9b8e
+	/* and for the GSSAPI key exchange */
6cf9b8e
+	monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1);
Jan F. Chadima 69dd72f
+#endif		
6cf9b8e
 
3cd4899
 	if (auth_opts->permit_pty_flag) {
6cf9b8e
 		monitor_permit(mon_dispatch, MONITOR_REQ_PTY, 1);
bbf61da
@@ -1695,6 +1712,13 @@ monitor_apply_keystate(struct monitor *p
132f8f8
 # endif
132f8f8
 #endif /* WITH_OPENSSL */
132f8f8
 		kex->kex[KEX_C25519_SHA256] = kexc25519_server;
Jan F. Chadima 69dd72f
+#ifdef GSSAPI
Jan F. Chadima 69dd72f
+	if (options.gss_keyex) {
Jan F. Chadima 69dd72f
+		kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server;
Jan F. Chadima 69dd72f
+		kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_server;
Jan F. Chadima 69dd72f
+		kex->kex[KEX_GSS_GEX_SHA1] = kexgss_server;
Jan F. Chadima 69dd72f
+	}
Jan F. Chadima 69dd72f
+#endif
132f8f8
 		kex->load_host_public_key=&get_hostkey_public_by_type;
132f8f8
 		kex->load_host_private_key=&get_hostkey_private_by_type;
132f8f8
 		kex->host_key_index=&get_hostkey_index;
bbf61da
@@ -1785,7 +1809,7 @@ mm_answer_gss_setup_ctx(int sock, struct
bbf61da
 	u_char *p;
bbf61da
 	int r;
Jan F. Chadima 69dd72f
 
6cf9b8e
-	if (!options.gss_authentication)
Jan F. Chadima 69dd72f
+	if (!options.gss_authentication && !options.gss_keyex)
6cf9b8e
 		fatal("%s: GSSAPI authentication not enabled", __func__);
Jan F. Chadima 69dd72f
 
bbf61da
 	if ((r = sshbuf_get_string(m, &p, &len)) != 0)
bbf61da
@@ -1818,7 +1842,7 @@ mm_answer_gss_accept_ctx(int sock, struc
Jan F. Chadima 69dd72f
 	OM_uint32 flags = 0; /* GSI needs this */
bbf61da
 	int r;
Jan F. Chadima 69dd72f
 
6cf9b8e
-	if (!options.gss_authentication)
Jan F. Chadima 69dd72f
+	if (!options.gss_authentication && !options.gss_keyex)
6cf9b8e
 		fatal("%s: GSSAPI authentication not enabled", __func__);
6cf9b8e
 
bbf61da
 	if ((r = ssh_gssapi_get_buffer_desc(m, &in)) != 0)
bbf61da
@@ -1839,6 +1863,7 @@ mm_answer_gss_accept_ctx(int sock, struc
Jan F. Chadima 69dd72f
 		monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 0);
Jan F. Chadima 69dd72f
 		monitor_permit(mon_dispatch, MONITOR_REQ_GSSUSEROK, 1);
Jan F. Chadima 69dd72f
 		monitor_permit(mon_dispatch, MONITOR_REQ_GSSCHECKMIC, 1);
Jan F. Chadima 69dd72f
+		monitor_permit(mon_dispatch, MONITOR_REQ_GSSSIGN, 1);
Jan F. Chadima 69dd72f
 	}
Jan F. Chadima 69dd72f
 	return (0);
Jan F. Chadima 69dd72f
 }
bbf61da
@@ -1850,7 +1875,7 @@ mm_answer_gss_checkmic(int sock, struct
Jan F. Chadima 69dd72f
 	OM_uint32 ret;
bbf61da
 	int r;
Jan F. Chadima 69dd72f
 
6cf9b8e
-	if (!options.gss_authentication)
Jan F. Chadima 69dd72f
+	if (!options.gss_authentication && !options.gss_keyex)
6cf9b8e
 		fatal("%s: GSSAPI authentication not enabled", __func__);
6cf9b8e
 
bbf61da
 	if ((r = ssh_gssapi_get_buffer_desc(m, &gssbuf)) != 0 ||
bbf61da
@@ -1880,10 +1905,11 @@ mm_answer_gss_userok(int sock, struct ss
bbf61da
 	int r, authenticated;
5b55d09
 	const char *displayname;
Jan F. Chadima 69dd72f
 
6cf9b8e
-	if (!options.gss_authentication)
Jan F. Chadima 69dd72f
+	if (!options.gss_authentication && !options.gss_keyex)
6cf9b8e
 		fatal("%s: GSSAPI authentication not enabled", __func__);
6cf9b8e
 
6cf9b8e
-	authenticated = authctxt->valid && ssh_gssapi_userok(authctxt->user);
6cf9b8e
+	authenticated = authctxt->valid &&
Jan F. Chadima 69dd72f
+	    ssh_gssapi_userok(authctxt->user, authctxt->pw);
Jan F. Chadima 69dd72f
 
bbf61da
 	sshbuf_reset(m);
bbf61da
 	if ((r = sshbuf_put_u32(m, authenticated)) != 0)
bbf61da
@@ -1900,5 +1926,74 @@ mm_answer_gss_userok(int sock, struct ss
Jan F. Chadima 69dd72f
 	/* Monitor loop will terminate if authenticated */
Jan F. Chadima 69dd72f
 	return (authenticated);
Jan F. Chadima 69dd72f
 }
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+int 
bbf61da
+mm_answer_gss_sign(int socket, struct sshbuf *m)
Jan F. Chadima 69dd72f
+{
Jan F. Chadima 69dd72f
+	gss_buffer_desc data;
Jan F. Chadima 69dd72f
+	gss_buffer_desc hash = GSS_C_EMPTY_BUFFER;
Jan F. Chadima 69dd72f
+	OM_uint32 major, minor;
bbf61da
+	int r;
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	if (!options.gss_authentication && !options.gss_keyex)
Jan F. Chadima 69dd72f
+		fatal("In GSSAPI monitor when GSSAPI is disabled");
Jan F. Chadima 69dd72f
+
bbf61da
+	if ((r = sshbuf_get_string(m, (u_char **)&data.value, &data.length)) != 0)
bbf61da
+		fatal("%s: buffer error: %s", __func__, ssh_err(r));
Jan F. Chadima 69dd72f
+	if (data.length != 20) 
Jan F. Chadima 69dd72f
+		fatal("%s: data length incorrect: %d", __func__, 
Jan F. Chadima 69dd72f
+		    (int) data.length);
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	/* Save the session ID on the first time around */
Jan F. Chadima 69dd72f
+	if (session_id2_len == 0) {
Jan F. Chadima 69dd72f
+		session_id2_len = data.length;
Jan F. Chadima 69dd72f
+		session_id2 = xmalloc(session_id2_len);
Jan F. Chadima 69dd72f
+		memcpy(session_id2, data.value, session_id2_len);
Jan F. Chadima 69dd72f
+	}
Jan F. Chadima 69dd72f
+	major = ssh_gssapi_sign(gsscontext, &data, &hash);
Jan F. Chadima 69dd72f
+
84822b5
+	free(data.value);
Jan F. Chadima 69dd72f
+
bbf61da
+	sshbuf_reset(m);
bbf61da
+	if ((r = sshbuf_put_u32(m, major)) != 0 ||
bbf61da
+	    (r = sshbuf_put_string(m, hash.value, hash.length)) != 0)
bbf61da
+		fatal("%s: buffer error: %s", __func__, ssh_err(r));
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	mm_request_send(socket, MONITOR_ANS_GSSSIGN, m);
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	gss_release_buffer(&minor, &hash);
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	/* Turn on getpwnam permissions */
Jan F. Chadima 69dd72f
+	monitor_permit(mon_dispatch, MONITOR_REQ_PWNAM, 1);
Jan F. Chadima 69dd72f
+	
Jan F. Chadima 69dd72f
+	/* And credential updating, for when rekeying */
Jan F. Chadima 69dd72f
+	monitor_permit(mon_dispatch, MONITOR_REQ_GSSUPCREDS, 1);
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	return (0);
Jan F. Chadima 69dd72f
+}
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+int
bbf61da
+mm_answer_gss_updatecreds(int socket, struct sshbuf *m) {
Jan F. Chadima 69dd72f
+	ssh_gssapi_ccache store;
bbf61da
+	int ok, r;
Jan F. Chadima 69dd72f
+
bbf61da
+	if ((r = sshbuf_get_cstring(m, &store.envvar, NULL)) != 0 ||
bbf61da
+	    (r = sshbuf_get_cstring(m, &store.envval, NULL)) != 0)
bbf61da
+		fatal("%s: buffer error: %s", __func__, ssh_err(r));
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	ok = ssh_gssapi_update_creds(&store);
Jan F. Chadima 69dd72f
+
84822b5
+	free(store.envvar);
84822b5
+	free(store.envval);
Jan F. Chadima 69dd72f
+
bbf61da
+	sshbuf_reset(m);
bbf61da
+	if ((r = sshbuf_put_u32(m, ok)) != 0)
bbf61da
+		fatal("%s: buffer error: %s", __func__, ssh_err(r));
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	mm_request_send(socket, MONITOR_ANS_GSSUPCREDS, m);
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	return(0);
Jan F. Chadima 69dd72f
+}
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
 #endif /* GSSAPI */
Jan F. Chadima 69dd72f
 
5b55d09
diff -up openssh/monitor.h.gsskex openssh/monitor.h
bbf61da
--- openssh/monitor.h.gsskex	2018-08-22 11:47:33.263216069 +0200
bbf61da
+++ openssh/monitor.h	2018-08-22 11:47:33.313216473 +0200
bbf61da
@@ -58,6 +58,8 @@ enum monitor_reqtype {
8a29ded
 #ifdef WITH_SELINUX
8a29ded
 	MONITOR_REQ_AUTHROLE = 80,
8a29ded
 #endif
8a29ded
+	MONITOR_REQ_GSSSIGN = 82, MONITOR_ANS_GSSSIGN = 83,
8a29ded
+	MONITOR_REQ_GSSUPCREDS = 84, MONITOR_ANS_GSSUPCREDS = 85,
8a29ded
 
8a29ded
 	MONITOR_REQ_PAM_START = 100,
8a29ded
 	MONITOR_REQ_PAM_ACCOUNT = 102, MONITOR_ANS_PAM_ACCOUNT = 103,
5b55d09
diff -up openssh/monitor_wrap.c.gsskex openssh/monitor_wrap.c
bbf61da
--- openssh/monitor_wrap.c.gsskex	2018-08-22 11:47:33.313216473 +0200
bbf61da
+++ openssh/monitor_wrap.c	2018-08-22 13:27:38.665669643 +0200
bbf61da
@@ -1004,7 +1004,7 @@ mm_ssh_gssapi_checkmic(Gssctxt *ctx, gss
Jan F. Chadima 69dd72f
 }
Jan F. Chadima 69dd72f
 
Jan F. Chadima 69dd72f
 int
Jan F. Chadima 69dd72f
-mm_ssh_gssapi_userok(char *user)
Jan F. Chadima 69dd72f
+mm_ssh_gssapi_userok(char *user, struct passwd *pw)
Jan F. Chadima 69dd72f
 {
bbf61da
 	struct sshbuf *m;
bbf61da
 	int r, authenticated = 0;
bbf61da
@@ -1023,4 +1023,52 @@ mm_ssh_gssapi_userok(char *user)
Jan F. Chadima 69dd72f
 	debug3("%s: user %sauthenticated",__func__, authenticated ? "" : "not ");
Jan F. Chadima 69dd72f
 	return (authenticated);
Jan F. Chadima 69dd72f
 }
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+OM_uint32
Jan F. Chadima 69dd72f
+mm_ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_desc *data, gss_buffer_desc *hash)
Jan F. Chadima 69dd72f
+{
bbf61da
+	struct sshbuf *m;
Jan F. Chadima 69dd72f
+	OM_uint32 major;
bbf61da
+	int r;
Jan F. Chadima 69dd72f
+
bbf61da
+	if ((m = sshbuf_new()) == NULL)
bbf61da
+		fatal("%s: sshbuf_new failed", __func__);
bbf61da
+	if ((r = sshbuf_put_string(m, data->value, data->length)) != 0)
bbf61da
+		fatal("%s: buffer error: %s", __func__, ssh_err(r));
Jan F. Chadima 69dd72f
+
bbf61da
+	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSSIGN, m);
bbf61da
+	mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSSIGN, m);
Jan F. Chadima 69dd72f
+
bbf61da
+	if ((r = sshbuf_get_u32(m, &major)) != 0 ||
bbf61da
+	    (r = sshbuf_get_string(m, (u_char **)&hash->value, &hash->length)) != 0)
bbf61da
+		fatal("%s: buffer error: %s", __func__, ssh_err(r));
Jan F. Chadima 69dd72f
+
bbf61da
+	sshbuf_free(m);
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	return(major);
Jan F. Chadima 69dd72f
+}
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+int
Jan F. Chadima 69dd72f
+mm_ssh_gssapi_update_creds(ssh_gssapi_ccache *store)
Jan F. Chadima 69dd72f
+{
bbf61da
+	struct sshbuf *m;
bbf61da
+	int ok, r;
Jan F. Chadima 69dd72f
+
bbf61da
+	if ((m = sshbuf_new()) == NULL)
bbf61da
+		fatal("%s: sshbuf_new failed", __func__);
Jan F. Chadima 69dd72f
+
bbf61da
+	if ((r = sshbuf_put_cstring(m, store->envvar ? store->envvar : "")) != 0 ||
bbf61da
+	    (r = sshbuf_put_cstring(m, store->envval ? store->envval : "")) != 0)
bbf61da
+		fatal("%s: buffer error: %s", __func__, ssh_err(r));
3e1dd6c
+
bbf61da
+	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSUPCREDS, m);
bbf61da
+	mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSUPCREDS, m);
Jan F. Chadima 69dd72f
+
bbf61da
+	if ((r = sshbuf_get_u32(m, &ok)) != 0)
bbf61da
+		fatal("%s: buffer error: %s", __func__, ssh_err(r));
Jan F. Chadima 69dd72f
+
bbf61da
+	sshbuf_free(m);
3e1dd6c
+
Jan F. Chadima 69dd72f
+	return (ok);
Jan F. Chadima 69dd72f
+}
Jan F. Chadima 69dd72f
 #endif /* GSSAPI */
5b55d09
diff -up openssh/monitor_wrap.h.gsskex openssh/monitor_wrap.h
bbf61da
--- openssh/monitor_wrap.h.gsskex	2018-08-22 11:47:33.263216069 +0200
bbf61da
+++ openssh/monitor_wrap.h	2018-08-22 11:47:33.313216473 +0200
bbf61da
@@ -63,8 +63,10 @@ int mm_sshkey_verify(const struct sshkey
Jan F. Chadima 69dd72f
 OM_uint32 mm_ssh_gssapi_server_ctx(Gssctxt **, gss_OID);
Jan F. Chadima 69dd72f
 OM_uint32 mm_ssh_gssapi_accept_ctx(Gssctxt *,
Jan F. Chadima 69dd72f
    gss_buffer_desc *, gss_buffer_desc *, OM_uint32 *);
Jan F. Chadima 69dd72f
-int mm_ssh_gssapi_userok(char *user);
Jan F. Chadima 69dd72f
+int mm_ssh_gssapi_userok(char *user, struct passwd *);
Jan F. Chadima 69dd72f
 OM_uint32 mm_ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t);
Jan F. Chadima 69dd72f
+OM_uint32 mm_ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t);
Jan F. Chadima 69dd72f
+int mm_ssh_gssapi_update_creds(ssh_gssapi_ccache *);
Jan F. Chadima 69dd72f
 #endif
Jan F. Chadima 69dd72f
 
Jan F. Chadima 69dd72f
 #ifdef USE_PAM
5b55d09
diff -up openssh/readconf.c.gsskex openssh/readconf.c
bbf61da
--- openssh/readconf.c.gsskex	2018-08-20 07:57:29.000000000 +0200
bbf61da
+++ openssh/readconf.c	2018-08-22 13:28:17.487982869 +0200
bbf61da
@@ -161,6 +161,8 @@ typedef enum {
Jan F. Chadima 69dd72f
 	oClearAllForwardings, oNoHostAuthenticationForLocalhost,
Jan F. Chadima 69dd72f
 	oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
Jan F. Chadima 69dd72f
 	oAddressFamily, oGssAuthentication, oGssDelegateCreds,
Jan F. Chadima 69dd72f
+	oGssTrustDns, oGssKeyEx, oGssClientIdentity, oGssRenewalRekey,
Jan F. Chadima 69dd72f
+	oGssServerIdentity, 
Jan F. Chadima 69dd72f
 	oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
bbf61da
 	oSendEnv, oSetEnv, oControlPath, oControlMaster, oControlPersist,
Jan F. Chadima 69dd72f
 	oHashKnownHosts,
bbf61da
@@ -201,10 +203,19 @@ static struct {
17b491b
 	/* Sometimes-unsupported options */
Jan F. Chadima 69dd72f
 #if defined(GSSAPI)
Jan F. Chadima 69dd72f
 	{ "gssapiauthentication", oGssAuthentication },
Jan F. Chadima 69dd72f
+	{ "gssapikeyexchange", oGssKeyEx },
Jan F. Chadima 69dd72f
 	{ "gssapidelegatecredentials", oGssDelegateCreds },
Jan F. Chadima 69dd72f
+	{ "gssapitrustdns", oGssTrustDns },
Jan F. Chadima 69dd72f
+	{ "gssapiclientidentity", oGssClientIdentity },
Jan F. Chadima 69dd72f
+	{ "gssapiserveridentity", oGssServerIdentity },
Jan F. Chadima 69dd72f
+	{ "gssapirenewalforcesrekey", oGssRenewalRekey },
17b491b
 # else
Jan F. Chadima 69dd72f
 	{ "gssapiauthentication", oUnsupported },
Jan F. Chadima 69dd72f
+	{ "gssapikeyexchange", oUnsupported },
Jan F. Chadima 69dd72f
 	{ "gssapidelegatecredentials", oUnsupported },
Jan F. Chadima 69dd72f
+	{ "gssapitrustdns", oUnsupported },
Jan F. Chadima 69dd72f
+	{ "gssapiclientidentity", oUnsupported },
Jan F. Chadima 69dd72f
+	{ "gssapirenewalforcesrekey", oUnsupported },
Jan F. Chadima 69dd72f
 #endif
17b491b
 #ifdef ENABLE_PKCS11
17b491b
 	{ "smartcarddevice", oPKCS11Provider },
bbf61da
@@ -973,10 +984,30 @@ parse_time:
Jan F. Chadima 69dd72f
 		intptr = &options->gss_authentication;
Jan F. Chadima 69dd72f
 		goto parse_flag;
Jan F. Chadima 69dd72f
 
Jan F. Chadima 69dd72f
+	case oGssKeyEx:
Jan F. Chadima 69dd72f
+		intptr = &options->gss_keyex;
Jan F. Chadima 69dd72f
+		goto parse_flag;
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
 	case oGssDelegateCreds:
Jan F. Chadima 69dd72f
 		intptr = &options->gss_deleg_creds;
Jan F. Chadima 69dd72f
 		goto parse_flag;
Jan F. Chadima 69dd72f
 
Jan F. Chadima 69dd72f
+	case oGssTrustDns:
Jan F. Chadima 69dd72f
+		intptr = &options->gss_trust_dns;
Jan F. Chadima 69dd72f
+		goto parse_flag;
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	case oGssClientIdentity:
Jan F. Chadima 69dd72f
+		charptr = &options->gss_client_identity;
Jan F. Chadima 69dd72f
+		goto parse_string;
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	case oGssServerIdentity:
Jan F. Chadima 69dd72f
+		charptr = &options->gss_server_identity;
Jan F. Chadima 69dd72f
+		goto parse_string;
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	case oGssRenewalRekey:
Jan F. Chadima 69dd72f
+		intptr = &options->gss_renewal_rekey;
Jan F. Chadima 69dd72f
+		goto parse_flag;
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
 	case oBatchMode:
Jan F. Chadima 69dd72f
 		intptr = &options->batch_mode;
Jan F. Chadima 69dd72f
 		goto parse_flag;
bbf61da
@@ -1817,7 +1848,12 @@ initialize_options(Options * options)
Jan F. Chadima 69dd72f
 	options->pubkey_authentication = -1;
Jan F. Chadima 69dd72f
 	options->challenge_response_authentication = -1;
Jan F. Chadima 69dd72f
 	options->gss_authentication = -1;
Jan F. Chadima 69dd72f
+	options->gss_keyex = -1;
Jan F. Chadima 69dd72f
 	options->gss_deleg_creds = -1;
Jan F. Chadima 69dd72f
+	options->gss_trust_dns = -1;
Jan F. Chadima 69dd72f
+	options->gss_renewal_rekey = -1;
Jan F. Chadima 69dd72f
+	options->gss_client_identity = NULL;
Jan F. Chadima 69dd72f
+	options->gss_server_identity = NULL;
Jan F. Chadima 69dd72f
 	options->password_authentication = -1;
Jan F. Chadima 69dd72f
 	options->kbd_interactive_authentication = -1;
Jan F. Chadima 69dd72f
 	options->kbd_interactive_devices = NULL;
bbf61da
@@ -1962,8 +1998,14 @@ fill_default_options(Options * options)
Jan F. Chadima 69dd72f
 		options->challenge_response_authentication = 1;
Jan F. Chadima 69dd72f
 	if (options->gss_authentication == -1)
Jan F. Chadima 69dd72f
 		options->gss_authentication = 0;
Jan F. Chadima 69dd72f
+	if (options->gss_keyex == -1)
Jan F. Chadima 69dd72f
+		options->gss_keyex = 0;
Jan F. Chadima 69dd72f
 	if (options->gss_deleg_creds == -1)
Jan F. Chadima 69dd72f
 		options->gss_deleg_creds = 0;
Jan F. Chadima 69dd72f
+	if (options->gss_trust_dns == -1)
Jan F. Chadima 69dd72f
+		options->gss_trust_dns = 0;
Jan F. Chadima 69dd72f
+	if (options->gss_renewal_rekey == -1)
Jan F. Chadima 69dd72f
+		options->gss_renewal_rekey = 0;
Jan F. Chadima 69dd72f
 	if (options->password_authentication == -1)
Jan F. Chadima 69dd72f
 		options->password_authentication = 1;
Jan F. Chadima 69dd72f
 	if (options->kbd_interactive_authentication == -1)
5b55d09
diff -up openssh/readconf.h.gsskex openssh/readconf.h
bbf61da
--- openssh/readconf.h.gsskex	2018-08-20 07:57:29.000000000 +0200
bbf61da
+++ openssh/readconf.h	2018-08-22 11:47:33.314216481 +0200
bbf61da
@@ -40,7 +40,12 @@ typedef struct {
Jan F. Chadima 69dd72f
 	int     challenge_response_authentication;
Jan F. Chadima 69dd72f
 					/* Try S/Key or TIS, authentication. */
Jan F. Chadima 69dd72f
 	int     gss_authentication;	/* Try GSS authentication */
Jan F. Chadima 69dd72f
+	int     gss_keyex;		/* Try GSS key exchange */
Jan F. Chadima 69dd72f
 	int     gss_deleg_creds;	/* Delegate GSS credentials */
Jan F. Chadima 69dd72f
+	int	gss_trust_dns;		/* Trust DNS for GSS canonicalization */
Jan F. Chadima 69dd72f
+	int	gss_renewal_rekey;	/* Credential renewal forces rekey */
Jan F. Chadima 69dd72f
+	char    *gss_client_identity;   /* Principal to initiate GSSAPI with */
Jan F. Chadima 69dd72f
+	char    *gss_server_identity;   /* GSSAPI target principal */
Jan F. Chadima 69dd72f
 	int     password_authentication;	/* Try password
Jan F. Chadima 69dd72f
 						 * authentication. */
Jan F. Chadima 69dd72f
 	int     kbd_interactive_authentication; /* Try keyboard-interactive auth. */
5b55d09
diff -up openssh/regress/cert-hostkey.sh.gsskex openssh/regress/cert-hostkey.sh
bbf61da
--- openssh/regress/cert-hostkey.sh.gsskex	2018-08-20 07:57:29.000000000 +0200
bbf61da
+++ openssh/regress/cert-hostkey.sh	2018-08-22 11:47:33.314216481 +0200
bbf61da
@@ -66,7 +66,7 @@ touch $OBJ/host_revoked_plain
132f8f8
 touch $OBJ/host_revoked_cert
5878ebb
 cat $OBJ/host_ca_key.pub $OBJ/host_ca_key2.pub > $OBJ/host_revoked_ca
3e1dd6c
 
3e1dd6c
-PLAIN_TYPES=`$SSH -Q key-plain | sed 's/^ssh-dss/ssh-dsa/g;s/^ssh-//'`
3e1dd6c
+PLAIN_TYPES=`$SSH -Q key-plain | grep -v null | sed 's/^ssh-dss/ssh-dsa/g;s/^ssh-//'`
3e1dd6c
 
5878ebb
 if echo "$PLAIN_TYPES" | grep '^rsa$' >/dev/null 2>&1 ; then
5878ebb
 	PLAIN_TYPES="$PLAIN_TYPES rsa-sha2-256 rsa-sha2-512"
5b55d09
diff -up openssh/regress/cert-userkey.sh.gsskex openssh/regress/cert-userkey.sh
bbf61da
--- openssh/regress/cert-userkey.sh.gsskex	2018-08-20 07:57:29.000000000 +0200
bbf61da
+++ openssh/regress/cert-userkey.sh	2018-08-22 11:47:33.314216481 +0200
3f55133
@@ -7,7 +7,7 @@ rm -f $OBJ/authorized_keys_$USER $OBJ/us
3e1dd6c
 cp $OBJ/sshd_proxy $OBJ/sshd_proxy_bak
3f55133
 cp $OBJ/ssh_proxy $OBJ/ssh_proxy_bak
3e1dd6c
 
3e1dd6c
-PLAIN_TYPES=`$SSH -Q key-plain | sed 's/^ssh-dss/ssh-dsa/;s/^ssh-//'`
3e1dd6c
+PLAIN_TYPES=`$SSH -Q key-plain | grep -v null | sed 's/^ssh-dss/ssh-dsa/;s/^ssh-//'`
3cd4899
 EXTRA_TYPES=""
3e1dd6c
 
5878ebb
 if echo "$PLAIN_TYPES" | grep '^rsa$' >/dev/null 2>&1 ; then
5b55d09
diff -up openssh/regress/kextype.sh.gsskex openssh/regress/kextype.sh
bbf61da
--- openssh/regress/kextype.sh.gsskex	2018-08-20 07:57:29.000000000 +0200
bbf61da
+++ openssh/regress/kextype.sh	2018-08-22 11:47:33.315216489 +0200
132f8f8
@@ -14,6 +14,9 @@ echo "KexAlgorithms=$KEXOPT" >> $OBJ/ssh
3e1dd6c
 
3e1dd6c
 tries="1 2 3 4"
3e1dd6c
 for k in `${SSH} -Q kex`; do
3e1dd6c
+	if [ $k = "gss-gex-sha1-" -o $k = "gss-group1-sha1-" -o $k = "gss-group14-sha1-" ]; then
3e1dd6c
+		continue
3e1dd6c
+	fi
3e1dd6c
 	verbose "kex $k"
3e1dd6c
 	for i in $tries; do
3e1dd6c
 		${SSH} -F $OBJ/ssh_proxy -o KexAlgorithms=$k x true
5b55d09
diff -up openssh/regress/rekey.sh.gsskex openssh/regress/rekey.sh
bbf61da
--- openssh/regress/rekey.sh.gsskex	2018-08-20 07:57:29.000000000 +0200
bbf61da
+++ openssh/regress/rekey.sh	2018-08-22 11:47:33.315216489 +0200
1900351
@@ -38,6 +38,9 @@ increase_datafile_size 300
3e1dd6c
 
3e1dd6c
 opts=""
3e1dd6c
 for i in `${SSH} -Q kex`; do
3e1dd6c
+	if [ $i = "gss-gex-sha1-" -o $i = "gss-group1-sha1-" -o $i = "gss-group14-sha1-" ]; then
3e1dd6c
+		continue
3e1dd6c
+	fi
3e1dd6c
 	opts="$opts KexAlgorithms=$i"
3e1dd6c
 done
3e1dd6c
 for i in `${SSH} -Q cipher`; do
1900351
@@ -56,6 +59,9 @@ done
3e1dd6c
 if ${SSH} -Q cipher-auth | grep '^.*$' >/dev/null 2>&1 ; then
3e1dd6c
   for c in `${SSH} -Q cipher-auth`; do
3e1dd6c
     for kex in `${SSH} -Q kex`; do
3e1dd6c
+	if [ $kex = "gss-gex-sha1-" -o $kex = "gss-group1-sha1-" -o $kex = "gss-group14-sha1-" ]; then
3e1dd6c
+		continue
3e1dd6c
+	fi
3e1dd6c
 	verbose "client rekey $c $kex"
1900351
 	ssh_data_rekeying "KexAlgorithms=$kex" -oRekeyLimit=256k -oCiphers=$c
3e1dd6c
     done
5b55d09
diff -up openssh/servconf.c.gsskex openssh/servconf.c
bbf61da
--- openssh/servconf.c.gsskex	2018-08-22 11:47:33.296216335 +0200
bbf61da
+++ openssh/servconf.c	2018-08-22 13:28:41.905179879 +0200
bbf61da
@@ -124,8 +124,10 @@ initialize_server_options(ServerOptions
Jan F. Chadima 69dd72f
 	options->kerberos_ticket_cleanup = -1;
Jan F. Chadima 69dd72f
 	options->kerberos_get_afs_token = -1;
Jan F. Chadima 69dd72f
 	options->gss_authentication=-1;
Jan F. Chadima 69dd72f
+	options->gss_keyex = -1;
Jan F. Chadima 69dd72f
 	options->gss_cleanup_creds = -1;
535d341
 	options->gss_strict_acceptor = -1;
Jan F. Chadima 69dd72f
+	options->gss_store_rekey = -1;
Jan F. Chadima 69dd72f
 	options->password_authentication = -1;
Jan F. Chadima 69dd72f
 	options->kbd_interactive_authentication = -1;
Jan F. Chadima 69dd72f
 	options->challenge_response_authentication = -1;
bbf61da
@@ -334,10 +336,14 @@ fill_default_server_options(ServerOption
Jan F. Chadima 69dd72f
 		options->kerberos_get_afs_token = 0;
Jan F. Chadima 69dd72f
 	if (options->gss_authentication == -1)
Jan F. Chadima 69dd72f
 		options->gss_authentication = 0;
Jan F. Chadima 69dd72f
+	if (options->gss_keyex == -1)
Jan F. Chadima 69dd72f
+		options->gss_keyex = 0;
Jan F. Chadima 69dd72f
 	if (options->gss_cleanup_creds == -1)
Jan F. Chadima 69dd72f
 		options->gss_cleanup_creds = 1;
535d341
 	if (options->gss_strict_acceptor == -1)
17b491b
 		options->gss_strict_acceptor = 1;
Jan F. Chadima 69dd72f
+	if (options->gss_store_rekey == -1)
Jan F. Chadima 69dd72f
+		options->gss_store_rekey = 0;
Jan F. Chadima 69dd72f
 	if (options->password_authentication == -1)
Jan F. Chadima 69dd72f
 		options->password_authentication = 1;
Jan F. Chadima 69dd72f
 	if (options->kbd_interactive_authentication == -1)
bbf61da
@@ -484,7 +490,7 @@ typedef enum {
3f55133
 	sHostKeyAlgorithms,
132f8f8
 	sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile,
535d341
 	sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor,
bbf61da
-	sAcceptEnv, sSetEnv, sPermitTunnel,
bbf61da
+	sGssKeyEx, sGssStoreRekey, sAcceptEnv, sSetEnv, sPermitTunnel,
bbf61da
 	sMatch, sPermitOpen, sPermitListen, sForceCommand, sChrootDirectory,
Jan F. Chadima 69dd72f
 	sUsePrivilegeSeparation, sAllowAgentForwarding,
3e1dd6c
 	sHostCertificate,
bbf61da
@@ -559,11 +565,17 @@ static struct {
Jan F. Chadima 69dd72f
 	{ "gssapiauthentication", sGssAuthentication, SSHCFG_ALL },
Jan F. Chadima 69dd72f
 	{ "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL },
535d341
 	{ "gssapistrictacceptorcheck", sGssStrictAcceptor, SSHCFG_GLOBAL },
Jan F. Chadima 69dd72f
+	{ "gssapikeyexchange", sGssKeyEx, SSHCFG_GLOBAL },
Jan F. Chadima 69dd72f
+	{ "gssapistorecredentialsonrekey", sGssStoreRekey, SSHCFG_GLOBAL },
Jan F. Chadima 69dd72f
 #else
Jan F. Chadima 69dd72f
 	{ "gssapiauthentication", sUnsupported, SSHCFG_ALL },
Jan F. Chadima 69dd72f
 	{ "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL },
535d341
 	{ "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL },
Jan F. Chadima 69dd72f
+	{ "gssapikeyexchange", sUnsupported, SSHCFG_GLOBAL },
Jan F. Chadima 69dd72f
+	{ "gssapistorecredentialsonrekey", sUnsupported, SSHCFG_GLOBAL },
Jan F. Chadima 69dd72f
 #endif
Jan F. Chadima 69dd72f
+	{ "gssusesessionccache", sUnsupported, SSHCFG_GLOBAL },
Jan F. Chadima 69dd72f
+	{ "gssapiusesessioncredcache", sUnsupported, SSHCFG_GLOBAL },
Jan F. Chadima 69dd72f
 	{ "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL },
Jan F. Chadima 69dd72f
 	{ "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL },
Jan F. Chadima 69dd72f
 	{ "challengeresponseauthentication", sChallengeResponseAuthentication, SSHCFG_GLOBAL },
bbf61da
@@ -1463,6 +1475,10 @@ process_server_config_line(ServerOptions
Jan F. Chadima 69dd72f
 		intptr = &options->gss_authentication;
Jan F. Chadima 69dd72f
 		goto parse_flag;
Jan F. Chadima 69dd72f
 
Jan F. Chadima 69dd72f
+	case sGssKeyEx:
Jan F. Chadima 69dd72f
+		intptr = &options->gss_keyex;
Jan F. Chadima 69dd72f
+		goto parse_flag;
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
 	case sGssCleanupCreds:
Jan F. Chadima 69dd72f
 		intptr = &options->gss_cleanup_creds;
Jan F. Chadima 69dd72f
 		goto parse_flag;
bbf61da
@@ -1471,6 +1487,10 @@ process_server_config_line(ServerOptions
535d341
 		intptr = &options->gss_strict_acceptor;
535d341
 		goto parse_flag;
Jan F. Chadima 69dd72f
 
Jan F. Chadima 69dd72f
+	case sGssStoreRekey:
Jan F. Chadima 69dd72f
+		intptr = &options->gss_store_rekey;
Jan F. Chadima 69dd72f
+		goto parse_flag;
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
 	case sPasswordAuthentication:
Jan F. Chadima 69dd72f
 		intptr = &options->password_authentication;
Jan F. Chadima 69dd72f
 		goto parse_flag;
bbf61da
@@ -2560,6 +2580,9 @@ dump_config(ServerOptions *o)
d9e6186
 #ifdef GSSAPI
Jan F. Chadima 69dd72f
 	dump_cfg_fmtint(sGssAuthentication, o->gss_authentication);
Jan F. Chadima 69dd72f
 	dump_cfg_fmtint(sGssCleanupCreds, o->gss_cleanup_creds);
Jan F. Chadima 69dd72f
+	dump_cfg_fmtint(sGssKeyEx, o->gss_keyex);
Jan F. Chadima 69dd72f
+	dump_cfg_fmtint(sGssStrictAcceptor, o->gss_strict_acceptor);
Jan F. Chadima 69dd72f
+	dump_cfg_fmtint(sGssStoreRekey, o->gss_store_rekey);
Jan F. Chadima 69dd72f
 #endif
3e1dd6c
 	dump_cfg_fmtint(sPasswordAuthentication, o->password_authentication);
3e1dd6c
 	dump_cfg_fmtint(sKbdInteractiveAuthentication,
5b55d09
diff -up openssh/servconf.h.gsskex openssh/servconf.h
bbf61da
--- openssh/servconf.h.gsskex	2018-08-22 11:47:33.296216335 +0200
bbf61da
+++ openssh/servconf.h	2018-08-22 11:47:33.316216497 +0200
bbf61da
@@ -124,8 +124,10 @@ typedef struct {
Jan F. Chadima 69dd72f
 	int     kerberos_get_afs_token;		/* If true, try to get AFS token if
Jan F. Chadima 69dd72f
 						 * authenticated with Kerberos. */
Jan F. Chadima 69dd72f
 	int     gss_authentication;	/* If true, permit GSSAPI authentication */
Jan F. Chadima 69dd72f
+	int     gss_keyex;		/* If true, permit GSSAPI key exchange */
Jan F. Chadima 69dd72f
 	int     gss_cleanup_creds;	/* If true, destroy cred cache on logout */
535d341
 	int     gss_strict_acceptor;	/* If true, restrict the GSSAPI acceptor name */
Jan F. Chadima 69dd72f
+	int 	gss_store_rekey;
Jan F. Chadima 69dd72f
 	int     password_authentication;	/* If true, permit password
Jan F. Chadima 69dd72f
 						 * authentication. */
Jan F. Chadima 69dd72f
 	int     kbd_interactive_authentication;	/* If true, permit */
5b55d09
diff -up openssh/ssh_config.5.gsskex openssh/ssh_config.5
bbf61da
--- openssh/ssh_config.5.gsskex	2018-08-20 07:57:29.000000000 +0200
bbf61da
+++ openssh/ssh_config.5	2018-08-22 11:47:33.316216497 +0200
bbf61da
@@ -718,10 +718,40 @@ The default is
13073f8
 Specifies whether user authentication based on GSSAPI is allowed.
Jan F. Chadima 69dd72f
 The default is
6cf9b8e
 .Cm no .
Jan F. Chadima 69dd72f
+.It Cm GSSAPIClientIdentity
Jan F. Chadima 69dd72f
+If set, specifies the GSSAPI client identity that ssh should use when 
Jan F. Chadima 69dd72f
+connecting to the server. The default is unset, which means that the default 
Jan F. Chadima 69dd72f
+identity will be used.
Jan F. Chadima 69dd72f
 .It Cm GSSAPIDelegateCredentials
Jan F. Chadima 69dd72f
 Forward (delegate) credentials to the server.
Jan F. Chadima 69dd72f
 The default is
6cf9b8e
 .Cm no .
6cf9b8e
+.It Cm GSSAPIKeyExchange
6cf9b8e
+Specifies whether key exchange based on GSSAPI may be used. When using
6cf9b8e
+GSSAPI key exchange the server need not have a host key.
6cf9b8e
+The default is
6cf9b8e
+.Dq no .
Jan F. Chadima 69dd72f
+.It Cm GSSAPIRenewalForcesRekey
Jan F. Chadima 69dd72f
+If set to 
Jan F. Chadima 69dd72f
+.Dq yes
Jan F. Chadima 69dd72f
+then renewal of the client's GSSAPI credentials will force the rekeying of the
Jan F. Chadima 69dd72f
+ssh connection. With a compatible server, this can delegate the renewed 
Jan F. Chadima 69dd72f
+credentials to a session on the server.
Jan F. Chadima 69dd72f
+The default is
Jan F. Chadima 69dd72f
+.Dq no .
6cf9b8e
+.It Cm GSSAPIServerIdentity
6cf9b8e
+If set, specifies the GSSAPI server identity that ssh should expect when 
6cf9b8e
+connecting to the server. The default is unset, which means that the
6cf9b8e
+expected GSSAPI server identity will be determined from the target
6cf9b8e
+hostname.
Jan F. Chadima 69dd72f
+.It Cm GSSAPITrustDns
Jan F. Chadima 69dd72f
+Set to 
Jan F. Chadima 69dd72f
+.Dq yes to indicate that the DNS is trusted to securely canonicalize
Jan F. Chadima 69dd72f
+the name of the host being connected to. If 
Jan F. Chadima 69dd72f
+.Dq no, the hostname entered on the
Jan F. Chadima 69dd72f
+command line will be passed untouched to the GSSAPI library.
Jan F. Chadima 69dd72f
+The default is
Jan F. Chadima 69dd72f
+.Dq no .
Jan F. Chadima 69dd72f
 .It Cm HashKnownHosts
Jan F. Chadima 69dd72f
 Indicates that
Jan F. Chadima 69dd72f
 .Xr ssh 1
5b55d09
diff -up openssh/ssh_config.gsskex openssh/ssh_config
bbf61da
--- openssh/ssh_config.gsskex	2018-08-22 11:47:33.289216279 +0200
bbf61da
+++ openssh/ssh_config	2018-08-22 11:47:33.316216497 +0200
5b55d09
@@ -24,6 +24,8 @@
535d341
 #   HostbasedAuthentication no
535d341
 #   GSSAPIAuthentication no
535d341
 #   GSSAPIDelegateCredentials no
535d341
+#   GSSAPIKeyExchange no
535d341
+#   GSSAPITrustDNS no
535d341
 #   BatchMode no
535d341
 #   CheckHostIP yes
535d341
 #   AddressFamily any
5b55d09
diff -up openssh/sshconnect2.c.gsskex openssh/sshconnect2.c
bbf61da
--- openssh/sshconnect2.c.gsskex	2018-08-20 07:57:29.000000000 +0200
bbf61da
+++ openssh/sshconnect2.c	2018-08-22 13:33:01.674275795 +0200
5b55d09
@@ -82,6 +82,124 @@ extern char *client_version_string;
5b55d09
 extern char *server_version_string;
5b55d09
 extern Options options;
5b55d09
 
5b55d09
+/* XXX from auth.h -- refactoring move these useful functions away of client context*/
5b55d09
+
5b55d09
+/*
5b55d09
+ * Returns the remote DNS hostname as a string. The returned string must not
5b55d09
+ * be freed. NB. this will usually trigger a DNS query the first time it is
5b55d09
+ * called.
5b55d09
+ * This function does additional checks on the hostname to mitigate some
5b55d09
+ * attacks on legacy rhosts-style authentication.
5b55d09
+ * XXX is RhostsRSAAuthentication vulnerable to these?
5b55d09
+ * XXX Can we remove these checks? (or if not, remove RhostsRSAAuthentication?)
5b55d09
+ */
5b55d09
+
5b55d09
+static char *
5b55d09
+remote_hostname(struct ssh *ssh)
5b55d09
+{
5b55d09
+	struct sockaddr_storage from;
5b55d09
+	socklen_t fromlen;
5b55d09
+	struct addrinfo hints, *ai, *aitop;
5b55d09
+	char name[NI_MAXHOST], ntop2[NI_MAXHOST];
5b55d09
+	const char *ntop = ssh_remote_ipaddr(ssh);
5b55d09
+
5b55d09
+	/* Get IP address of client. */
5b55d09
+	fromlen = sizeof(from);
5b55d09
+	memset(&from, 0, sizeof(from));
5b55d09
+	if (getpeername(ssh_packet_get_connection_in(ssh),
5b55d09
+	    (struct sockaddr *)&from, &fromlen) < 0) {
5b55d09
+		debug("getpeername failed: %.100s", strerror(errno));
5b55d09
+		return strdup(ntop);
5b55d09
+	}
5b55d09
+
5b55d09
+	ipv64_normalise_mapped(&from, &fromlen);
5b55d09
+	if (from.ss_family == AF_INET6)
5b55d09
+		fromlen = sizeof(struct sockaddr_in6);
5b55d09
+
5b55d09
+	debug3("Trying to reverse map address %.100s.", ntop);
5b55d09
+	/* Map the IP address to a host name. */
5b55d09
+	if (getnameinfo((struct sockaddr *)&from, fromlen, name, sizeof(name),
5b55d09
+	    NULL, 0, NI_NAMEREQD) != 0) {
5b55d09
+		/* Host name not found.  Use ip address. */
5b55d09
+		return strdup(ntop);
5b55d09
+	}
5b55d09
+
5b55d09
+	/*
5b55d09
+	 * if reverse lookup result looks like a numeric hostname,
5b55d09
+	 * someone is trying to trick us by PTR record like following:
5b55d09
+	 *	1.1.1.10.in-addr.arpa.	IN PTR	2.3.4.5
5b55d09
+	 */
5b55d09
+	memset(&hints, 0, sizeof(hints));
5b55d09
+	hints.ai_socktype = SOCK_DGRAM;	/*dummy*/
5b55d09
+	hints.ai_flags = AI_NUMERICHOST;
5b55d09
+	if (getaddrinfo(name, NULL, &hints, &ai) == 0) {
5b55d09
+		logit("Nasty PTR record \"%s\" is set up for %s, ignoring",
5b55d09
+		    name, ntop);
5b55d09
+		freeaddrinfo(ai);
5b55d09
+		return strdup(ntop);
5b55d09
+	}
5b55d09
+
5b55d09
+	/* Names are stored in lowercase. */
5b55d09
+	lowercase(name);
5b55d09
+
5b55d09
+	/*
5b55d09
+	 * Map it back to an IP address and check that the given
5b55d09
+	 * address actually is an address of this host.  This is
5b55d09
+	 * necessary because anyone with access to a name server can
5b55d09
+	 * define arbitrary names for an IP address. Mapping from
5b55d09
+	 * name to IP address can be trusted better (but can still be
5b55d09
+	 * fooled if the intruder has access to the name server of
5b55d09
+	 * the domain).
5b55d09
+	 */
5b55d09
+	memset(&hints, 0, sizeof(hints));
5b55d09
+	hints.ai_family = from.ss_family;
5b55d09
+	hints.ai_socktype = SOCK_STREAM;
5b55d09
+	if (getaddrinfo(name, NULL, &hints, &aitop) != 0) {
5b55d09
+		logit("reverse mapping checking getaddrinfo for %.700s "
5b55d09
+		    "[%s] failed.", name, ntop);
5b55d09
+		return strdup(ntop);
5b55d09
+	}
5b55d09
+	/* Look for the address from the list of addresses. */
5b55d09
+	for (ai = aitop; ai; ai = ai->ai_next) {
5b55d09
+		if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop2,
5b55d09
+		    sizeof(ntop2), NULL, 0, NI_NUMERICHOST) == 0 &&
5b55d09
+		    (strcmp(ntop, ntop2) == 0))
5b55d09
+				break;
5b55d09
+	}
5b55d09
+	freeaddrinfo(aitop);
5b55d09
+	/* If we reached the end of the list, the address was not there. */
5b55d09
+	if (ai == NULL) {
5b55d09
+		/* Address not found for the host name. */
5b55d09
+		logit("Address %.100s maps to %.600s, but this does not "
5b55d09
+		    "map back to the address.", ntop, name);
5b55d09
+		return strdup(ntop);
5b55d09
+	}
5b55d09
+	return strdup(name);
5b55d09
+}
5b55d09
+
5b55d09
+/*
5b55d09
+ * Return the canonical name of the host in the other side of the current
5b55d09
+ * connection.  The host name is cached, so it is efficient to call this
5b55d09
+ * several times.
5b55d09
+ */
5b55d09
+
5b55d09
+const char *
5b55d09
+get_canonical_hostname(struct ssh *ssh, int use_dns)
5b55d09
+{
5b55d09
+	static char *dnsname;
5b55d09
+
5b55d09
+	if (!use_dns)
5b55d09
+		return ssh_remote_ipaddr(ssh);
5b55d09
+	else if (dnsname != NULL)
5b55d09
+		return dnsname;
5b55d09
+	else {
5b55d09
+		dnsname = remote_hostname(ssh);
5b55d09
+		return dnsname;
5b55d09
+	}
5b55d09
+}
5b55d09
+
5b55d09
+
5b55d09
+
5b55d09
 /*
5b55d09
  * SSH2 key exchange
5b55d09
  */
5b55d09
@@ -162,9 +280,34 @@ ssh_kex2(char *host, struct sockaddr *ho
132f8f8
 	struct kex *kex;
132f8f8
 	int r;
Jan F. Chadima 69dd72f
 
Jan F. Chadima 69dd72f
+#ifdef GSSAPI
Jan F. Chadima 69dd72f
+	char *orig = NULL, *gss = NULL;
Jan F. Chadima 69dd72f
+	char *gss_host = NULL;
Jan F. Chadima 69dd72f
+#endif
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
 	xxx_host = host;
Jan F. Chadima 69dd72f
 	xxx_hostaddr = hostaddr;
Jan F. Chadima 69dd72f
 
Jan F. Chadima 69dd72f
+#ifdef GSSAPI
Jan F. Chadima 69dd72f
+	if (options.gss_keyex) {
Jan F. Chadima 69dd72f
+		/* Add the GSSAPI mechanisms currently supported on this 
Jan F. Chadima 69dd72f
+		 * client to the key exchange algorithm proposal */
9a804fa
+		orig = options.kex_algorithms;
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+		if (options.gss_trust_dns)
b487a6d
+			gss_host = (char *)get_canonical_hostname(active_state, 1);
Jan F. Chadima 69dd72f
+		else
Jan F. Chadima 69dd72f
+			gss_host = host;
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+		gss = ssh_gssapi_client_mechanisms(gss_host, options.gss_client_identity);
Jan F. Chadima 69dd72f
+		if (gss) {
Jan F. Chadima 69dd72f
+			debug("Offering GSSAPI proposal: %s", gss);
9a804fa
+			xasprintf(&options.kex_algorithms,
Jan F. Chadima 69dd72f
+			    "%s,%s", gss, orig);
Jan F. Chadima 69dd72f
+		}
Jan F. Chadima 69dd72f
+	}
Jan F. Chadima 69dd72f
+#endif
Jan F. Chadima 69dd72f
+
13073f8
 	if ((s = kex_names_cat(options.kex_algorithms, "ext-info-c")) == NULL)
13073f8
 		fatal("%s: kex_names_cat", __func__);
13073f8
 	myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal(s);
bbf61da
@@ -194,6 +337,17 @@ ssh_kex2(char *host, struct sockaddr *ho
3f55133
 		    order_hostkeyalgs(host, hostaddr, port));
3f55133
 	}
Jan F. Chadima 69dd72f
 
Jan F. Chadima 69dd72f
+#ifdef GSSAPI
Jan F. Chadima 69dd72f
+	/* If we've got GSSAPI algorithms, then we also support the
Jan F. Chadima 69dd72f
+	 * 'null' hostkey, as a last resort */
Jan F. Chadima 69dd72f
+	if (options.gss_keyex && gss) {
Jan F. Chadima 69dd72f
+		orig = myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS];
dba154f
+		xasprintf(&myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS],
Jan F. Chadima 69dd72f
+		    "%s,null", orig);
84822b5
+		free(gss);
Jan F. Chadima 69dd72f
+	}
Jan F. Chadima 69dd72f
+#endif
Jan F. Chadima 69dd72f
+
84822b5
 	if (options.rekey_limit || options.rekey_interval)
17b491b
 		packet_set_rekey_limits(options.rekey_limit,
17b491b
 		    options.rekey_interval);
bbf61da
@@ -214,11 +368,31 @@ ssh_kex2(char *host, struct sockaddr *ho
Jan F. Chadima 69dd72f
 	kex->kex[KEX_ECDH_SHA2] = kexecdh_client;
132f8f8
 # endif
1900351
 #endif
Jan F. Chadima 69dd72f
+#ifdef GSSAPI
Jan F. Chadima 69dd72f
+	if (options.gss_keyex) {
Jan F. Chadima 69dd72f
+		kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_client;
Jan F. Chadima 69dd72f
+		kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_client;
Jan F. Chadima 69dd72f
+		kex->kex[KEX_GSS_GEX_SHA1] = kexgss_client;
Jan F. Chadima 69dd72f
+	}
Jan F. Chadima 69dd72f
+#endif
132f8f8
 	kex->kex[KEX_C25519_SHA256] = kexc25519_client;
Jan F. Chadima 69dd72f
 	kex->client_version_string=client_version_string;
Jan F. Chadima 69dd72f
 	kex->server_version_string=server_version_string;
Jan F. Chadima 69dd72f
 	kex->verify_host_key=&verify_host_key_callback;
Jan F. Chadima 69dd72f
 
Jan F. Chadima 69dd72f
+#ifdef GSSAPI
Jan F. Chadima 69dd72f
+	if (options.gss_keyex) {
Jan F. Chadima 69dd72f
+		kex->gss_deleg_creds = options.gss_deleg_creds;
Jan F. Chadima 69dd72f
+		kex->gss_trust_dns = options.gss_trust_dns;
Jan F. Chadima 69dd72f
+		kex->gss_client = options.gss_client_identity;
Jan F. Chadima 69dd72f
+		if (options.gss_server_identity) {
Jan F. Chadima 69dd72f
+			kex->gss_host = options.gss_server_identity;
Jan F. Chadima 69dd72f
+		} else {
Jan F. Chadima 69dd72f
+			kex->gss_host = gss_host;
Jan F. Chadima 69dd72f
+        }
Jan F. Chadima 69dd72f
+	}
Jan F. Chadima 69dd72f
+#endif
Jan F. Chadima 69dd72f
+
5b55d09
 	ssh_dispatch_run_fatal(active_state, DISPATCH_BLOCK, &kex->done);
Jan F. Chadima 69dd72f
 
13073f8
 	/* remove ext-info from the KEX proposals for rekeying */
bbf61da
@@ -314,6 +488,7 @@ int	input_gssapi_token(int type, u_int32
5b55d09
 int	input_gssapi_hash(int type, u_int32_t, struct ssh *);
5b55d09
 int	input_gssapi_error(int, u_int32_t, struct ssh *);
5b55d09
 int	input_gssapi_errtok(int, u_int32_t, struct ssh *);
Jan F. Chadima 69dd72f
+int	userauth_gsskeyex(Authctxt *authctxt);
Jan F. Chadima 69dd72f
 #endif
Jan F. Chadima 69dd72f
 
Jan F. Chadima 69dd72f
 void	userauth(Authctxt *, char *);
bbf61da
@@ -330,6 +505,11 @@ static char *authmethods_get(void);
Jan F. Chadima 69dd72f
 
Jan F. Chadima 69dd72f
 Authmethod authmethods[] = {
Jan F. Chadima 69dd72f
 #ifdef GSSAPI
Jan F. Chadima 69dd72f
+	{"gssapi-keyex",
Jan F. Chadima 69dd72f
+		userauth_gsskeyex,
Jan F. Chadima 69dd72f
+		NULL,
Jan F. Chadima 69dd72f
+		&options.gss_authentication,
Jan F. Chadima 69dd72f
+		NULL},
Jan F. Chadima 69dd72f
 	{"gssapi-with-mic",
Jan F. Chadima 69dd72f
 		userauth_gssapi,
Jan F. Chadima 69dd72f
 		NULL,
bbf61da
@@ -657,19 +837,31 @@ userauth_gssapi(Authctxt *authctxt)
Jan F. Chadima 69dd72f
 	static u_int mech = 0;
Jan F. Chadima 69dd72f
 	OM_uint32 min;
bbf61da
 	int r, ok = 0;
Jan F. Chadima 69dd72f
+	const char *gss_host;
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+	if (options.gss_server_identity)
Jan F. Chadima 69dd72f
+		gss_host = options.gss_server_identity;
Jan F. Chadima 69dd72f
+	else if (options.gss_trust_dns)
b487a6d
+		gss_host = get_canonical_hostname(active_state, 1);
Jan F. Chadima 69dd72f
+	else
Jan F. Chadima 69dd72f
+		gss_host = authctxt->host;
Jan F. Chadima 69dd72f
 
Jan F. Chadima 69dd72f
 	/* Try one GSSAPI method at a time, rather than sending them all at
Jan F. Chadima 69dd72f
 	 * once. */
Jan F. Chadima 69dd72f
 
Jan F. Chadima 69dd72f
 	if (gss_supported == NULL)
Jan F. Chadima 69dd72f
-		gss_indicate_mechs(&min, &gss_supported);
Jan F. Chadima 69dd72f
+		if (GSS_ERROR(gss_indicate_mechs(&min, &gss_supported))) {
Jan F. Chadima 69dd72f
+			gss_supported = NULL;
Jan F. Chadima 69dd72f
+			return 0;
Jan F. Chadima 69dd72f
+		}
Jan F. Chadima 69dd72f
 
Jan F. Chadima 69dd72f
 	/* Check to see if the mechanism is usable before we offer it */
Jan F. Chadima 69dd72f
 	while (mech < gss_supported->count && !ok) {
Jan F. Chadima 69dd72f
 		/* My DER encoding requires length<128 */
Jan F. Chadima 69dd72f
 		if (gss_supported->elements[mech].length < 128 &&
bbf61da
 		    ssh_gssapi_check_mechanism(&gssctxt,
Jan F. Chadima 69dd72f
-		    &gss_supported->elements[mech], authctxt->host)) {
Jan F. Chadima 69dd72f
+		    &gss_supported->elements[mech], gss_host, 
Jan F. Chadima 69dd72f
+                    options.gss_client_identity)) {
Jan F. Chadima 69dd72f
 			ok = 1; /* Mechanism works */
Jan F. Chadima 69dd72f
 		} else {
Jan F. Chadima 69dd72f
 			mech++;
90edc0c
@@ -906,6 +1098,51 @@ input_gssapi_error(int type, u_int32_t p
84822b5
 	free(lang);
bbf61da
 	return r;
Jan F. Chadima 69dd72f
 }
Jan F. Chadima 69dd72f
+
Jan F. Chadima 69dd72f
+int
Jan F. Chadima 69dd72f
+userauth_gsskeyex(Authctxt *authctxt)
Jan F. Chadima 69dd72f
+{
bbf61da
+	struct sshbuf *b = NULL;
Jan F. Chadima