vishalmishra434 / rpms / openssh

Forked from rpms/openssh a month ago
Clone
Jakub Jelen def1de
diff --git a/Makefile.in b/Makefile.in
Jakub Jelen 51f5c1
index e7549470..b68c1710 100644
Jakub Jelen def1de
--- a/Makefile.in
Jakub Jelen def1de
+++ b/Makefile.in
Jakub Jelen 51f5c1
@@ -109,6 +109,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \
Jakub Jelen def1de
 	kex.o kexdh.o kexgex.o kexecdh.o kexc25519.o \
Jakub Jelen def1de
 	kexgexc.o kexgexs.o \
Jakub Jelen def1de
 	sntrup4591761.o kexsntrup4591761x25519.o kexgen.o \
Jakub Jelen def1de
+	kexgssc.o \
Jakub Jelen 51f5c1
 	sftp-realpath.o platform-pledge.o platform-tracing.o platform-misc.o \
Jakub Jelen 51f5c1
 	sshbuf-io.o
Jakub Jelen def1de
 
Jakub Jelen 51f5c1
@@ -125,7 +126,7 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o \
Jakub Jelen def1de
 	auth-bsdauth.o auth2-hostbased.o auth2-kbdint.o \
Jakub Jelen def1de
 	auth2-none.o auth2-passwd.o auth2-pubkey.o \
Jakub Jelen def1de
 	monitor.o monitor_wrap.o auth-krb5.o \
Jakub Jelen def1de
-	auth2-gss.o gss-serv.o gss-serv-krb5.o \
Jakub Jelen def1de
+	auth2-gss.o gss-serv.o gss-serv-krb5.o kexgsss.o \
Jakub Jelen def1de
 	loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \
Jakub Jelen 51f5c1
 	sftp-server.o sftp-common.o \
Jakub Jelen def1de
 	sandbox-null.o sandbox-rlimit.o sandbox-systrace.o sandbox-darwin.o \
Jakub Jelen def1de
diff --git a/auth.c b/auth.c
Jakub Jelen 51f5c1
index 086b8ebb..687c57b4 100644
Jakub Jelen def1de
--- a/auth.c
Jakub Jelen def1de
+++ b/auth.c
Jakub Jelen 51f5c1
@@ -400,7 +400,8 @@ auth_root_allowed(struct ssh *ssh, const char *method)
Jakub Jelen def1de
 	case PERMIT_NO_PASSWD:
Jakub Jelen def1de
 		if (strcmp(method, "publickey") == 0 ||
Jakub Jelen def1de
 		    strcmp(method, "hostbased") == 0 ||
Jakub Jelen def1de
-		    strcmp(method, "gssapi-with-mic") == 0)
Jakub Jelen def1de
+		    strcmp(method, "gssapi-with-mic") == 0 ||
Jakub Jelen def1de
+		    strcmp(method, "gssapi-keyex") == 0)
Jakub Jelen def1de
 			return 1;
Jakub Jelen def1de
 		break;
Jakub Jelen def1de
 	case PERMIT_FORCED_ONLY:
Jakub Jelen 51f5c1
@@ -724,99 +725,6 @@ fakepw(void)
Jakub Jelen def1de
 	return (&fake);
Jakub Jelen def1de
 }
Jakub Jelen def1de
 
Jakub Jelen def1de
-/*
Jakub Jelen def1de
- * Returns the remote DNS hostname as a string. The returned string must not
Jakub Jelen def1de
- * be freed. NB. this will usually trigger a DNS query the first time it is
Jakub Jelen def1de
- * called.
Jakub Jelen def1de
- * This function does additional checks on the hostname to mitigate some
Jakub Jelen def1de
- * attacks on legacy rhosts-style authentication.
Jakub Jelen def1de
- * XXX is RhostsRSAAuthentication vulnerable to these?
Jakub Jelen def1de
- * XXX Can we remove these checks? (or if not, remove RhostsRSAAuthentication?)
Jakub Jelen def1de
- */
Jakub Jelen def1de
-
Jakub Jelen def1de
-static char *
Jakub Jelen def1de
-remote_hostname(struct ssh *ssh)
Jakub Jelen def1de
-{
Jakub Jelen def1de
-	struct sockaddr_storage from;
Jakub Jelen def1de
-	socklen_t fromlen;
Jakub Jelen def1de
-	struct addrinfo hints, *ai, *aitop;
Jakub Jelen def1de
-	char name[NI_MAXHOST], ntop2[NI_MAXHOST];
Jakub Jelen def1de
-	const char *ntop = ssh_remote_ipaddr(ssh);
Jakub Jelen def1de
-
Jakub Jelen def1de
-	/* Get IP address of client. */
Jakub Jelen def1de
-	fromlen = sizeof(from);
Jakub Jelen def1de
-	memset(&from, 0, sizeof(from));
Jakub Jelen def1de
-	if (getpeername(ssh_packet_get_connection_in(ssh),
Jakub Jelen 36fef5
-	    (struct sockaddr *)&from, &fromlen) == -1) {
Jakub Jelen def1de
-		debug("getpeername failed: %.100s", strerror(errno));
Jakub Jelen 51f5c1
-		return xstrdup(ntop);
Jakub Jelen def1de
-	}
Jakub Jelen def1de
-
Jakub Jelen def1de
-	ipv64_normalise_mapped(&from, &fromlen);
Jakub Jelen def1de
-	if (from.ss_family == AF_INET6)
Jakub Jelen def1de
-		fromlen = sizeof(struct sockaddr_in6);
Jakub Jelen def1de
-
Jakub Jelen def1de
-	debug3("Trying to reverse map address %.100s.", ntop);
Jakub Jelen def1de
-	/* Map the IP address to a host name. */
Jakub Jelen def1de
-	if (getnameinfo((struct sockaddr *)&from, fromlen, name, sizeof(name),
Jakub Jelen def1de
-	    NULL, 0, NI_NAMEREQD) != 0) {
Jakub Jelen def1de
-		/* Host name not found.  Use ip address. */
Jakub Jelen 51f5c1
-		return xstrdup(ntop);
Jakub Jelen def1de
-	}
Jakub Jelen def1de
-
Jakub Jelen def1de
-	/*
Jakub Jelen def1de
-	 * if reverse lookup result looks like a numeric hostname,
Jakub Jelen def1de
-	 * someone is trying to trick us by PTR record like following:
Jakub Jelen def1de
-	 *	1.1.1.10.in-addr.arpa.	IN PTR	2.3.4.5
Jakub Jelen def1de
-	 */
Jakub Jelen def1de
-	memset(&hints, 0, sizeof(hints));
Jakub Jelen def1de
-	hints.ai_socktype = SOCK_DGRAM;	/*dummy*/
Jakub Jelen def1de
-	hints.ai_flags = AI_NUMERICHOST;
Jakub Jelen def1de
-	if (getaddrinfo(name, NULL, &hints, &ai) == 0) {
Jakub Jelen def1de
-		logit("Nasty PTR record \"%s\" is set up for %s, ignoring",
Jakub Jelen def1de
-		    name, ntop);
Jakub Jelen def1de
-		freeaddrinfo(ai);
Jakub Jelen 51f5c1
-		return xstrdup(ntop);
Jakub Jelen def1de
-	}
Jakub Jelen def1de
-
Jakub Jelen def1de
-	/* Names are stored in lowercase. */
Jakub Jelen def1de
-	lowercase(name);
Jakub Jelen def1de
-
Jakub Jelen def1de
-	/*
Jakub Jelen def1de
-	 * Map it back to an IP address and check that the given
Jakub Jelen def1de
-	 * address actually is an address of this host.  This is
Jakub Jelen def1de
-	 * necessary because anyone with access to a name server can
Jakub Jelen def1de
-	 * define arbitrary names for an IP address. Mapping from
Jakub Jelen def1de
-	 * name to IP address can be trusted better (but can still be
Jakub Jelen def1de
-	 * fooled if the intruder has access to the name server of
Jakub Jelen def1de
-	 * the domain).
Jakub Jelen def1de
-	 */
Jakub Jelen def1de
-	memset(&hints, 0, sizeof(hints));
Jakub Jelen def1de
-	hints.ai_family = from.ss_family;
Jakub Jelen def1de
-	hints.ai_socktype = SOCK_STREAM;
Jakub Jelen def1de
-	if (getaddrinfo(name, NULL, &hints, &aitop) != 0) {
Jakub Jelen def1de
-		logit("reverse mapping checking getaddrinfo for %.700s "
Jakub Jelen def1de
-		    "[%s] failed.", name, ntop);
Jakub Jelen 51f5c1
-		return xstrdup(ntop);
Jakub Jelen def1de
-	}
Jakub Jelen def1de
-	/* Look for the address from the list of addresses. */
Jakub Jelen def1de
-	for (ai = aitop; ai; ai = ai->ai_next) {
Jakub Jelen def1de
-		if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop2,
Jakub Jelen def1de
-		    sizeof(ntop2), NULL, 0, NI_NUMERICHOST) == 0 &&
Jakub Jelen def1de
-		    (strcmp(ntop, ntop2) == 0))
Jakub Jelen def1de
-				break;
Jakub Jelen def1de
-	}
Jakub Jelen def1de
-	freeaddrinfo(aitop);
Jakub Jelen def1de
-	/* If we reached the end of the list, the address was not there. */
Jakub Jelen def1de
-	if (ai == NULL) {
Jakub Jelen def1de
-		/* Address not found for the host name. */
Jakub Jelen def1de
-		logit("Address %.100s maps to %.600s, but this does not "
Jakub Jelen def1de
-		    "map back to the address.", ntop, name);
Jakub Jelen 51f5c1
-		return xstrdup(ntop);
Jakub Jelen def1de
-	}
Jakub Jelen 51f5c1
-	return xstrdup(name);
Jakub Jelen def1de
-}
Jakub Jelen def1de
-
Jakub Jelen def1de
 /*
Jakub Jelen def1de
  * Return the canonical name of the host in the other side of the current
Jakub Jelen def1de
  * connection.  The host name is cached, so it is efficient to call this
Jakub Jelen def1de
diff --git a/auth2-gss.c b/auth2-gss.c
Jakub Jelen def1de
index 9351e042..d6446c0c 100644
Jakub Jelen def1de
--- a/auth2-gss.c
Jakub Jelen def1de
+++ b/auth2-gss.c
Jakub Jelen def1de
@@ -1,7 +1,7 @@
Jakub Jelen def1de
 /* $OpenBSD: auth2-gss.c,v 1.29 2018/07/31 03:10:27 djm Exp $ */
Jakub Jelen def1de
 
Jakub Jelen def1de
 /*
Jakub Jelen def1de
- * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
Jakub Jelen def1de
+ * Copyright (c) 2001-2007 Simon Wilkinson. All rights reserved.
Jakub Jelen def1de
  *
Jakub Jelen def1de
  * Redistribution and use in source and binary forms, with or without
Jakub Jelen def1de
  * modification, are permitted provided that the following conditions
Jakub Jelen def1de
@@ -54,6 +54,48 @@ static int input_gssapi_mic(int type, u_int32_t plen, struct ssh *ssh);
Jakub Jelen def1de
 static int input_gssapi_exchange_complete(int type, u_int32_t plen, struct ssh *ssh);
Jakub Jelen def1de
 static int input_gssapi_errtok(int, u_int32_t, struct ssh *);
Jakub Jelen def1de
 
Jakub Jelen def1de
+/*
Jakub Jelen def1de
+ * The 'gssapi_keyex' userauth mechanism.
Jakub Jelen def1de
+ */
Jakub Jelen def1de
+static int
Jakub Jelen def1de
+userauth_gsskeyex(struct ssh *ssh)
Jakub Jelen def1de
+{
Jakub Jelen def1de
+	Authctxt *authctxt = ssh->authctxt;
Jakub Jelen def1de
+	int r, authenticated = 0;
Jakub Jelen def1de
+	struct sshbuf *b = NULL;
Jakub Jelen def1de
+	gss_buffer_desc mic, gssbuf;
Jakub Jelen def1de
+	u_char *p;
Jakub Jelen def1de
+	size_t len;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if ((r = sshpkt_get_string(ssh, &p, &len)) != 0 ||
Jakub Jelen def1de
+	    (r = sshpkt_get_end(ssh)) != 0)
Jakub Jelen def1de
+		fatal("%s: %s", __func__, ssh_err(r));
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if ((b = sshbuf_new()) == NULL)
Jakub Jelen def1de
+		fatal("%s: sshbuf_new failed", __func__);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	mic.value = p;
Jakub Jelen def1de
+	mic.length = len;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	ssh_gssapi_buildmic(b, authctxt->user, authctxt->service,
Jakub Jelen def1de
+	    "gssapi-keyex");
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if ((gssbuf.value = sshbuf_mutable_ptr(b)) == NULL)
Jakub Jelen def1de
+		fatal("%s: sshbuf_mutable_ptr failed", __func__);
Jakub Jelen def1de
+	gssbuf.length = sshbuf_len(b);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	/* gss_kex_context is NULL with privsep, so we can't check it here */
Jakub Jelen def1de
+	if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gss_kex_context,
Jakub Jelen def1de
+	    &gssbuf, &mic))))
Jakub Jelen def1de
+		authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user,
Jakub Jelen def1de
+		    authctxt->pw, 1));
Jakub Jelen def1de
+
Jakub Jelen def1de
+	sshbuf_free(b);
Jakub Jelen def1de
+	free(mic.value);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	return (authenticated);
Jakub Jelen def1de
+}
Jakub Jelen def1de
+
Jakub Jelen def1de
 /*
Jakub Jelen def1de
  * We only support those mechanisms that we know about (ie ones that we know
Jakub Jelen def1de
  * how to check local user kuserok and the like)
Jakub Jelen def1de
@@ -260,7 +302,8 @@ input_gssapi_exchange_complete(int type, u_int32_t plen, struct ssh *ssh)
Jakub Jelen def1de
 	if ((r = sshpkt_get_end(ssh)) != 0)
Jakub Jelen def1de
 		fatal("%s: %s", __func__, ssh_err(r));
Jakub Jelen def1de
 
Jakub Jelen def1de
-	authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user));
Jakub Jelen def1de
+	authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user,
Jakub Jelen def1de
+	    authctxt->pw, 1));
Jakub Jelen def1de
 
Jakub Jelen def1de
 	if ((!use_privsep || mm_is_monitor()) &&
Jakub Jelen def1de
 	    (displayname = ssh_gssapi_displayname()) != NULL)
Jakub Jelen def1de
@@ -306,7 +349,8 @@ input_gssapi_mic(int type, u_int32_t plen, struct ssh *ssh)
Jakub Jelen def1de
 	gssbuf.length = sshbuf_len(b);
Jakub Jelen def1de
 
Jakub Jelen def1de
 	if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gssctxt, &gssbuf, &mic))))
Jakub Jelen def1de
-		authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user));
Jakub Jelen def1de
+		authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user,
Jakub Jelen def1de
+		    authctxt->pw, 0));
Jakub Jelen def1de
 	else
Jakub Jelen def1de
 		logit("GSSAPI MIC check failed");
Jakub Jelen def1de
 
Jakub Jelen def1de
@@ -326,6 +370,12 @@ input_gssapi_mic(int type, u_int32_t plen, struct ssh *ssh)
Jakub Jelen def1de
 	return 0;
Jakub Jelen def1de
 }
Jakub Jelen def1de
 
Jakub Jelen def1de
+Authmethod method_gsskeyex = {
Jakub Jelen def1de
+	"gssapi-keyex",
Jakub Jelen def1de
+	userauth_gsskeyex,
Jakub Jelen def1de
+	&options.gss_authentication
Jakub Jelen def1de
+};
Jakub Jelen def1de
+
Jakub Jelen def1de
 Authmethod method_gssapi = {
Jakub Jelen def1de
 	"gssapi-with-mic",
Jakub Jelen def1de
 	userauth_gssapi,
Jakub Jelen def1de
diff --git a/auth2.c b/auth2.c
Jakub Jelen 51f5c1
index 0e776224..1c217268 100644
Jakub Jelen def1de
--- a/auth2.c
Jakub Jelen def1de
+++ b/auth2.c
Jakub Jelen 51f5c1
@@ -73,6 +73,7 @@ extern Authmethod method_passwd;
Jakub Jelen def1de
 extern Authmethod method_kbdint;
Jakub Jelen def1de
 extern Authmethod method_hostbased;
Jakub Jelen def1de
 #ifdef GSSAPI
Jakub Jelen def1de
+extern Authmethod method_gsskeyex;
Jakub Jelen def1de
 extern Authmethod method_gssapi;
Jakub Jelen def1de
 #endif
Jakub Jelen def1de
 
Jakub Jelen 51f5c1
@@ -80,6 +81,7 @@ Authmethod *authmethods[] = {
Jakub Jelen def1de
 	&method_none,
Jakub Jelen def1de
 	&method_pubkey,
Jakub Jelen def1de
 #ifdef GSSAPI
Jakub Jelen def1de
+	&method_gsskeyex,
Jakub Jelen def1de
 	&method_gssapi,
Jakub Jelen def1de
 #endif
Jakub Jelen def1de
 	&method_passwd,
Jakub Jelen def1de
diff --git a/canohost.c b/canohost.c
Jakub Jelen 51f5c1
index abea9c6e..8e81b519 100644
Jakub Jelen def1de
--- a/canohost.c
Jakub Jelen def1de
+++ b/canohost.c
Jakub Jelen def1de
@@ -35,6 +35,99 @@
Jakub Jelen def1de
 #include "canohost.h"
Jakub Jelen def1de
 #include "misc.h"
Jakub Jelen def1de
 
Jakub Jelen def1de
+/*
Jakub Jelen def1de
+ * Returns the remote DNS hostname as a string. The returned string must not
Jakub Jelen def1de
+ * be freed. NB. this will usually trigger a DNS query the first time it is
Jakub Jelen def1de
+ * called.
Jakub Jelen def1de
+ * This function does additional checks on the hostname to mitigate some
Jakub Jelen def1de
+ * attacks on legacy rhosts-style authentication.
Jakub Jelen def1de
+ * XXX is RhostsRSAAuthentication vulnerable to these?
Jakub Jelen def1de
+ * XXX Can we remove these checks? (or if not, remove RhostsRSAAuthentication?)
Jakub Jelen def1de
+ */
Jakub Jelen def1de
+
Jakub Jelen def1de
+char *
Jakub Jelen def1de
+remote_hostname(struct ssh *ssh)
Jakub Jelen def1de
+{
Jakub Jelen def1de
+	struct sockaddr_storage from;
Jakub Jelen def1de
+	socklen_t fromlen;
Jakub Jelen def1de
+	struct addrinfo hints, *ai, *aitop;
Jakub Jelen def1de
+	char name[NI_MAXHOST], ntop2[NI_MAXHOST];
Jakub Jelen def1de
+	const char *ntop = ssh_remote_ipaddr(ssh);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	/* Get IP address of client. */
Jakub Jelen def1de
+	fromlen = sizeof(from);
Jakub Jelen def1de
+	memset(&from, 0, sizeof(from));
Jakub Jelen def1de
+	if (getpeername(ssh_packet_get_connection_in(ssh),
Jakub Jelen 36fef5
+	    (struct sockaddr *)&from, &fromlen) == -1) {
Jakub Jelen def1de
+		debug("getpeername failed: %.100s", strerror(errno));
Jakub Jelen 51f5c1
+		return xstrdup(ntop);
Jakub Jelen def1de
+	}
Jakub Jelen def1de
+
Jakub Jelen def1de
+	ipv64_normalise_mapped(&from, &fromlen);
Jakub Jelen def1de
+	if (from.ss_family == AF_INET6)
Jakub Jelen def1de
+		fromlen = sizeof(struct sockaddr_in6);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	debug3("Trying to reverse map address %.100s.", ntop);
Jakub Jelen def1de
+	/* Map the IP address to a host name. */
Jakub Jelen def1de
+	if (getnameinfo((struct sockaddr *)&from, fromlen, name, sizeof(name),
Jakub Jelen def1de
+	    NULL, 0, NI_NAMEREQD) != 0) {
Jakub Jelen def1de
+		/* Host name not found.  Use ip address. */
Jakub Jelen 51f5c1
+		return xstrdup(ntop);
Jakub Jelen def1de
+	}
Jakub Jelen def1de
+
Jakub Jelen def1de
+	/*
Jakub Jelen def1de
+	 * if reverse lookup result looks like a numeric hostname,
Jakub Jelen def1de
+	 * someone is trying to trick us by PTR record like following:
Jakub Jelen def1de
+	 *	1.1.1.10.in-addr.arpa.	IN PTR	2.3.4.5
Jakub Jelen def1de
+	 */
Jakub Jelen def1de
+	memset(&hints, 0, sizeof(hints));
Jakub Jelen def1de
+	hints.ai_socktype = SOCK_DGRAM;	/*dummy*/
Jakub Jelen def1de
+	hints.ai_flags = AI_NUMERICHOST;
Jakub Jelen def1de
+	if (getaddrinfo(name, NULL, &hints, &ai) == 0) {
Jakub Jelen def1de
+		logit("Nasty PTR record \"%s\" is set up for %s, ignoring",
Jakub Jelen def1de
+		    name, ntop);
Jakub Jelen def1de
+		freeaddrinfo(ai);
Jakub Jelen 51f5c1
+		return xstrdup(ntop);
Jakub Jelen def1de
+	}
Jakub Jelen def1de
+
Jakub Jelen def1de
+	/* Names are stored in lowercase. */
Jakub Jelen def1de
+	lowercase(name);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	/*
Jakub Jelen def1de
+	 * Map it back to an IP address and check that the given
Jakub Jelen def1de
+	 * address actually is an address of this host.  This is
Jakub Jelen def1de
+	 * necessary because anyone with access to a name server can
Jakub Jelen def1de
+	 * define arbitrary names for an IP address. Mapping from
Jakub Jelen def1de
+	 * name to IP address can be trusted better (but can still be
Jakub Jelen def1de
+	 * fooled if the intruder has access to the name server of
Jakub Jelen def1de
+	 * the domain).
Jakub Jelen def1de
+	 */
Jakub Jelen def1de
+	memset(&hints, 0, sizeof(hints));
Jakub Jelen def1de
+	hints.ai_family = from.ss_family;
Jakub Jelen def1de
+	hints.ai_socktype = SOCK_STREAM;
Jakub Jelen def1de
+	if (getaddrinfo(name, NULL, &hints, &aitop) != 0) {
Jakub Jelen def1de
+		logit("reverse mapping checking getaddrinfo for %.700s "
Jakub Jelen def1de
+		    "[%s] failed.", name, ntop);
Jakub Jelen 51f5c1
+		return xstrdup(ntop);
Jakub Jelen def1de
+	}
Jakub Jelen def1de
+	/* Look for the address from the list of addresses. */
Jakub Jelen def1de
+	for (ai = aitop; ai; ai = ai->ai_next) {
Jakub Jelen def1de
+		if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop2,
Jakub Jelen def1de
+		    sizeof(ntop2), NULL, 0, NI_NUMERICHOST) == 0 &&
Jakub Jelen def1de
+		    (strcmp(ntop, ntop2) == 0))
Jakub Jelen def1de
+				break;
Jakub Jelen def1de
+	}
Jakub Jelen def1de
+	freeaddrinfo(aitop);
Jakub Jelen def1de
+	/* If we reached the end of the list, the address was not there. */
Jakub Jelen def1de
+	if (ai == NULL) {
Jakub Jelen def1de
+		/* Address not found for the host name. */
Jakub Jelen def1de
+		logit("Address %.100s maps to %.600s, but this does not "
Jakub Jelen def1de
+		    "map back to the address.", ntop, name);
Jakub Jelen 51f5c1
+		return xstrdup(ntop);
Jakub Jelen def1de
+	}
Jakub Jelen 51f5c1
+	return xstrdup(name);
Jakub Jelen def1de
+}
Jakub Jelen def1de
+
Jakub Jelen def1de
 void
Jakub Jelen def1de
 ipv64_normalise_mapped(struct sockaddr_storage *addr, socklen_t *len)
Jakub Jelen def1de
 {
Jakub Jelen def1de
diff --git a/canohost.h b/canohost.h
Jakub Jelen def1de
index 26d62855..0cadc9f1 100644
Jakub Jelen def1de
--- a/canohost.h
Jakub Jelen def1de
+++ b/canohost.h
Jakub Jelen def1de
@@ -15,6 +15,9 @@
Jakub Jelen def1de
 #ifndef _CANOHOST_H
Jakub Jelen def1de
 #define _CANOHOST_H
Jakub Jelen def1de
 
Jakub Jelen def1de
+struct ssh;
Jakub Jelen def1de
+
Jakub Jelen def1de
+char		*remote_hostname(struct ssh *);
Jakub Jelen def1de
 char		*get_peer_ipaddr(int);
Jakub Jelen def1de
 int		 get_peer_port(int);
Jakub Jelen def1de
 char		*get_local_ipaddr(int);
Jakub Jelen def1de
diff --git a/clientloop.c b/clientloop.c
Jakub Jelen 51f5c1
index ebd0dbca..1bdac6a4 100644
Jakub Jelen def1de
--- a/clientloop.c
Jakub Jelen def1de
+++ b/clientloop.c
Jakub Jelen def1de
@@ -112,6 +112,10 @@
Jakub Jelen def1de
 #include "ssherr.h"
Jakub Jelen def1de
 #include "hostfile.h"
Jakub Jelen def1de
 
Jakub Jelen def1de
+#ifdef GSSAPI
Jakub Jelen def1de
+#include "ssh-gss.h"
Jakub Jelen def1de
+#endif
Jakub Jelen def1de
+
Jakub Jelen def1de
 /* import options */
Jakub Jelen def1de
 extern Options options;
Jakub Jelen def1de
 
Jakub Jelen 51f5c1
@@ -1379,9 +1383,18 @@ client_loop(struct ssh *ssh, int have_pty, int escape_char_arg,
Jakub Jelen def1de
 			break;
Jakub Jelen def1de
 
Jakub Jelen def1de
 		/* Do channel operations unless rekeying in progress. */
Jakub Jelen def1de
-		if (!ssh_packet_is_rekeying(ssh))
Jakub Jelen def1de
+		if (!ssh_packet_is_rekeying(ssh)) {
Jakub Jelen def1de
 			channel_after_select(ssh, readset, writeset);
Jakub Jelen def1de
 
Jakub Jelen def1de
+#ifdef GSSAPI
Jakub Jelen def1de
+			if (options.gss_renewal_rekey &&
Jakub Jelen def1de
+			    ssh_gssapi_credentials_updated(NULL)) {
Jakub Jelen def1de
+				debug("credentials updated - forcing rekey");
Jakub Jelen def1de
+				need_rekeying = 1;
Jakub Jelen def1de
+			}
Jakub Jelen def1de
+#endif
Jakub Jelen def1de
+		}
Jakub Jelen def1de
+
Jakub Jelen def1de
 		/* Buffer input from the connection.  */
Jakub Jelen def1de
 		client_process_net_input(ssh, readset);
Jakub Jelen def1de
 
Jakub Jelen def1de
diff --git a/configure.ac b/configure.ac
Jakub Jelen 51f5c1
index b689db4b..efafb6bd 100644
Jakub Jelen def1de
--- a/configure.ac
Jakub Jelen def1de
+++ b/configure.ac
Jakub Jelen 51f5c1
@@ -674,6 +674,30 @@ main() { if (NSVersionOfRunTimeLibrary("System") >= (60 << 16))
Jakub Jelen def1de
 	    [Use tunnel device compatibility to OpenBSD])
Jakub Jelen def1de
 	AC_DEFINE([SSH_TUN_PREPEND_AF], [1],
Jakub Jelen def1de
 	    [Prepend the address family to IP tunnel traffic])
Jakub Jelen def1de
+	AC_MSG_CHECKING([if we have the Security Authorization Session API])
Jakub Jelen def1de
+	AC_TRY_COMPILE([#include <Security/AuthSession.h>],
Jakub Jelen def1de
+		[SessionCreate(0, 0);],
Jakub Jelen def1de
+		[ac_cv_use_security_session_api="yes"
Jakub Jelen def1de
+		 AC_DEFINE([USE_SECURITY_SESSION_API], [1],
Jakub Jelen def1de
+			[platform has the Security Authorization Session API])
Jakub Jelen def1de
+		 LIBS="$LIBS -framework Security"
Jakub Jelen def1de
+		 AC_MSG_RESULT([yes])],
Jakub Jelen def1de
+		[ac_cv_use_security_session_api="no"
Jakub Jelen def1de
+		 AC_MSG_RESULT([no])])
Jakub Jelen def1de
+	AC_MSG_CHECKING([if we have an in-memory credentials cache])
Jakub Jelen def1de
+	AC_TRY_COMPILE(
Jakub Jelen def1de
+		[#include <Kerberos/Kerberos.h>],
Jakub Jelen def1de
+		[cc_context_t c;
Jakub Jelen def1de
+		 (void) cc_initialize (&c, 0, NULL, NULL);],
Jakub Jelen def1de
+		[AC_DEFINE([USE_CCAPI], [1],
Jakub Jelen def1de
+			[platform uses an in-memory credentials cache])
Jakub Jelen def1de
+		 LIBS="$LIBS -framework Security"
Jakub Jelen def1de
+		 AC_MSG_RESULT([yes])
Jakub Jelen def1de
+		 if test "x$ac_cv_use_security_session_api" = "xno"; then
Jakub Jelen def1de
+			AC_MSG_ERROR([*** Need a security framework to use the credentials cache API ***])
Jakub Jelen def1de
+		fi],
Jakub Jelen def1de
+		[AC_MSG_RESULT([no])]
Jakub Jelen def1de
+	)
Jakub Jelen def1de
 	m4_pattern_allow([AU_IPv])
Jakub Jelen def1de
 	AC_CHECK_DECL([AU_IPv4], [],
Jakub Jelen def1de
 	    AC_DEFINE([AU_IPv4], [0], [System only supports IPv4 audit records])
Jakub Jelen def1de
diff --git a/gss-genr.c b/gss-genr.c
Jakub Jelen 51f5c1
index d56257b4..763a63ff 100644
Jakub Jelen def1de
--- a/gss-genr.c
Jakub Jelen def1de
+++ b/gss-genr.c
Jakub Jelen def1de
@@ -1,7 +1,7 @@
Jakub Jelen def1de
 /* $OpenBSD: gss-genr.c,v 1.26 2018/07/10 09:13:30 djm Exp $ */
Jakub Jelen def1de
 
Jakub Jelen def1de
 /*
Jakub Jelen def1de
- * Copyright (c) 2001-2007 Simon Wilkinson. All rights reserved.
Jakub Jelen def1de
+ * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved.
Jakub Jelen def1de
  *
Jakub Jelen def1de
  * Redistribution and use in source and binary forms, with or without
Jakub Jelen def1de
  * modification, are permitted provided that the following conditions
Jakub Jelen def1de
@@ -41,12 +41,36 @@
Jakub Jelen def1de
 #include "sshbuf.h"
Jakub Jelen def1de
 #include "log.h"
Jakub Jelen def1de
 #include "ssh2.h"
Jakub Jelen def1de
+#include "cipher.h"
Jakub Jelen def1de
+#include "sshkey.h"
Jakub Jelen def1de
+#include "kex.h"
Jakub Jelen def1de
+#include "digest.h"
Jakub Jelen def1de
+#include "packet.h"
Jakub Jelen def1de
 
Jakub Jelen def1de
 #include "ssh-gss.h"
Jakub Jelen def1de
 
Jakub Jelen def1de
 extern u_char *session_id2;
Jakub Jelen def1de
 extern u_int session_id2_len;
Jakub Jelen def1de
 
Jakub Jelen def1de
+typedef struct {
Jakub Jelen def1de
+	char *encoded;
Jakub Jelen def1de
+	gss_OID oid;
Jakub Jelen def1de
+} ssh_gss_kex_mapping;
Jakub Jelen def1de
+
Jakub Jelen def1de
+/*
Jakub Jelen def1de
+ * XXX - It would be nice to find a more elegant way of handling the
Jakub Jelen def1de
+ * XXX   passing of the key exchange context to the userauth routines
Jakub Jelen def1de
+ */
Jakub Jelen def1de
+
Jakub Jelen def1de
+Gssctxt *gss_kex_context = NULL;
Jakub Jelen def1de
+
Jakub Jelen def1de
+static ssh_gss_kex_mapping *gss_enc2oid = NULL;
Jakub Jelen def1de
+
Jakub Jelen def1de
+int
Jakub Jelen def1de
+ssh_gssapi_oid_table_ok(void) {
Jakub Jelen def1de
+	return (gss_enc2oid != NULL);
Jakub Jelen def1de
+}
Jakub Jelen def1de
+
Jakub Jelen def1de
 /* sshbuf_get for gss_buffer_desc */
Jakub Jelen def1de
 int
Jakub Jelen def1de
 ssh_gssapi_get_buffer_desc(struct sshbuf *b, gss_buffer_desc *g)
Jakub Jelen 51f5c1
@@ -62,6 +86,162 @@ ssh_gssapi_get_buffer_desc(struct sshbuf *b, gss_buffer_desc *g)
Jakub Jelen def1de
 	return 0;
Jakub Jelen def1de
 }
Jakub Jelen def1de
 
Jakub Jelen def1de
+/* sshpkt_get of gss_buffer_desc */
Jakub Jelen def1de
+int
Jakub Jelen def1de
+ssh_gssapi_sshpkt_get_buffer_desc(struct ssh *ssh, gss_buffer_desc *g)
Jakub Jelen def1de
+{
Jakub Jelen def1de
+	int r;
Jakub Jelen def1de
+	u_char *p;
Jakub Jelen def1de
+	size_t len;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if ((r = sshpkt_get_string(ssh, &p, &len)) != 0)
Jakub Jelen def1de
+		return r;
Jakub Jelen def1de
+	g->value = p;
Jakub Jelen def1de
+	g->length = len;
Jakub Jelen def1de
+	return 0;
Jakub Jelen def1de
+}
Jakub Jelen def1de
+
Jakub Jelen def1de
+/*
Jakub Jelen def1de
+ * Return a list of the gss-group1-sha1 mechanisms supported by this program
Jakub Jelen def1de
+ *
Jakub Jelen def1de
+ * We test mechanisms to ensure that we can use them, to avoid starting
Jakub Jelen def1de
+ * a key exchange with a bad mechanism
Jakub Jelen def1de
+ */
Jakub Jelen def1de
+
Jakub Jelen def1de
+char *
Jakub Jelen def1de
+ssh_gssapi_client_mechanisms(const char *host, const char *client,
Jakub Jelen def1de
+    const char *kex) {
Jakub Jelen def1de
+	gss_OID_set gss_supported = NULL;
Jakub Jelen def1de
+	OM_uint32 min_status;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if (GSS_ERROR(gss_indicate_mechs(&min_status, &gss_supported)))
Jakub Jelen def1de
+		return NULL;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	return ssh_gssapi_kex_mechs(gss_supported, ssh_gssapi_check_mechanism,
Jakub Jelen def1de
+	    host, client, kex);
Jakub Jelen def1de
+}
Jakub Jelen def1de
+
Jakub Jelen def1de
+char *
Jakub Jelen def1de
+ssh_gssapi_kex_mechs(gss_OID_set gss_supported, ssh_gssapi_check_fn *check,
Jakub Jelen def1de
+    const char *host, const char *client, const char *kex) {
Jakub Jelen def1de
+	struct sshbuf *buf = NULL;
Jakub Jelen def1de
+	size_t i;
Jakub Jelen 51f5c1
+	int r = SSH_ERR_ALLOC_FAIL;
Jakub Jelen 51f5c1
+	int oidpos, enclen;
Jakub Jelen def1de
+	char *mechs, *encoded;
Jakub Jelen def1de
+	u_char digest[SSH_DIGEST_MAX_LENGTH];
Jakub Jelen def1de
+	char deroid[2];
Jakub Jelen def1de
+	struct ssh_digest_ctx *md = NULL;
Jakub Jelen def1de
+	char *s, *cp, *p;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if (gss_enc2oid != NULL) {
Jakub Jelen def1de
+		for (i = 0; gss_enc2oid[i].encoded != NULL; i++)
Jakub Jelen def1de
+			free(gss_enc2oid[i].encoded);
Jakub Jelen def1de
+		free(gss_enc2oid);
Jakub Jelen def1de
+	}
Jakub Jelen def1de
+
Jakub Jelen def1de
+	gss_enc2oid = xmalloc(sizeof(ssh_gss_kex_mapping) *
Jakub Jelen def1de
+	    (gss_supported->count + 1));
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if ((buf = sshbuf_new()) == NULL)
Jakub Jelen def1de
+		fatal("%s: sshbuf_new failed", __func__);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	oidpos = 0;
Jakub Jelen def1de
+	s = cp = xstrdup(kex);
Jakub Jelen def1de
+	for (i = 0; i < gss_supported->count; i++) {
Jakub Jelen def1de
+		if (gss_supported->elements[i].length < 128 &&
Jakub Jelen def1de
+		    (*check)(NULL, &(gss_supported->elements[i]), host, client)) {
Jakub Jelen def1de
+
Jakub Jelen def1de
+			deroid[0] = SSH_GSS_OIDTYPE;
Jakub Jelen def1de
+			deroid[1] = gss_supported->elements[i].length;
Jakub Jelen def1de
+
Jakub Jelen def1de
+			if ((md = ssh_digest_start(SSH_DIGEST_MD5)) == NULL ||
Jakub Jelen def1de
+			    (r = ssh_digest_update(md, deroid, 2)) != 0 ||
Jakub Jelen def1de
+			    (r = ssh_digest_update(md,
Jakub Jelen def1de
+			        gss_supported->elements[i].elements,
Jakub Jelen def1de
+			        gss_supported->elements[i].length)) != 0 ||
Jakub Jelen def1de
+			    (r = ssh_digest_final(md, digest, sizeof(digest))) != 0)
Jakub Jelen def1de
+				fatal("%s: digest failed: %s", __func__,
Jakub Jelen def1de
+				    ssh_err(r));
Jakub Jelen def1de
+			ssh_digest_free(md);
Jakub Jelen def1de
+			md = NULL;
Jakub Jelen def1de
+
Jakub Jelen def1de
+			encoded = xmalloc(ssh_digest_bytes(SSH_DIGEST_MD5)
Jakub Jelen def1de
+			    * 2);
Jakub Jelen def1de
+			enclen = __b64_ntop(digest,
Jakub Jelen def1de
+			    ssh_digest_bytes(SSH_DIGEST_MD5), encoded,
Jakub Jelen def1de
+			    ssh_digest_bytes(SSH_DIGEST_MD5) * 2);
Jakub Jelen def1de
+
Jakub Jelen def1de
+			cp = strncpy(s, kex, strlen(kex));
Jakub Jelen def1de
+			for ((p = strsep(&cp, ",")); p && *p != '\0';
Jakub Jelen def1de
+				(p = strsep(&cp, ","))) {
Jakub Jelen def1de
+				if (sshbuf_len(buf) != 0 &&
Jakub Jelen def1de
+				    (r = sshbuf_put_u8(buf, ',')) != 0)
Jakub Jelen def1de
+					fatal("%s: sshbuf_put_u8 error: %s",
Jakub Jelen def1de
+					    __func__, ssh_err(r));
Jakub Jelen def1de
+				if ((r = sshbuf_put(buf, p, strlen(p))) != 0 ||
Jakub Jelen def1de
+				    (r = sshbuf_put(buf, encoded, enclen)) != 0)
Jakub Jelen def1de
+					fatal("%s: sshbuf_put error: %s",
Jakub Jelen def1de
+					    __func__, ssh_err(r));
Jakub Jelen def1de
+			}
Jakub Jelen def1de
+
Jakub Jelen def1de
+			gss_enc2oid[oidpos].oid = &(gss_supported->elements[i]);
Jakub Jelen def1de
+			gss_enc2oid[oidpos].encoded = encoded;
Jakub Jelen def1de
+			oidpos++;
Jakub Jelen def1de
+		}
Jakub Jelen def1de
+	}
Jakub Jelen def1de
+	free(s);
Jakub Jelen def1de
+	gss_enc2oid[oidpos].oid = NULL;
Jakub Jelen def1de
+	gss_enc2oid[oidpos].encoded = NULL;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if ((mechs = sshbuf_dup_string(buf)) == NULL)
Jakub Jelen def1de
+		fatal("%s: sshbuf_dup_string failed", __func__);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	sshbuf_free(buf);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if (strlen(mechs) == 0) {
Jakub Jelen def1de
+		free(mechs);
Jakub Jelen def1de
+		mechs = NULL;
Jakub Jelen def1de
+	}
Jakub Jelen def1de
+
Jakub Jelen def1de
+	return (mechs);
Jakub Jelen def1de
+}
Jakub Jelen def1de
+
Jakub Jelen def1de
+gss_OID
Jakub Jelen def1de
+ssh_gssapi_id_kex(Gssctxt *ctx, char *name, int kex_type) {
Jakub Jelen def1de
+	int i = 0;
Jakub Jelen def1de
+
Jakub Jelen def1de
+#define SKIP_KEX_NAME(type) \
Jakub Jelen def1de
+	case type: \
Jakub Jelen def1de
+		if (strlen(name) < sizeof(type##_ID)) \
Jakub Jelen def1de
+			return GSS_C_NO_OID; \
Jakub Jelen def1de
+		name += sizeof(type##_ID) - 1; \
Jakub Jelen def1de
+		break;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	switch (kex_type) {
Jakub Jelen def1de
+	SKIP_KEX_NAME(KEX_GSS_GRP1_SHA1)
Jakub Jelen def1de
+	SKIP_KEX_NAME(KEX_GSS_GRP14_SHA1)
Jakub Jelen def1de
+	SKIP_KEX_NAME(KEX_GSS_GRP14_SHA256)
Jakub Jelen def1de
+	SKIP_KEX_NAME(KEX_GSS_GRP16_SHA512)
Jakub Jelen def1de
+	SKIP_KEX_NAME(KEX_GSS_GEX_SHA1)
Jakub Jelen def1de
+	SKIP_KEX_NAME(KEX_GSS_NISTP256_SHA256)
Jakub Jelen def1de
+	SKIP_KEX_NAME(KEX_GSS_C25519_SHA256)
Jakub Jelen def1de
+	default:
Jakub Jelen def1de
+		return GSS_C_NO_OID;
Jakub Jelen def1de
+	}
Jakub Jelen def1de
+
Jakub Jelen def1de
+#undef SKIP_KEX_NAME
Jakub Jelen def1de
+
Jakub Jelen def1de
+	while (gss_enc2oid[i].encoded != NULL &&
Jakub Jelen def1de
+	    strcmp(name, gss_enc2oid[i].encoded) != 0)
Jakub Jelen def1de
+		i++;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if (gss_enc2oid[i].oid != NULL && ctx != NULL)
Jakub Jelen def1de
+		ssh_gssapi_set_oid(ctx, gss_enc2oid[i].oid);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	return gss_enc2oid[i].oid;
Jakub Jelen def1de
+}
Jakub Jelen def1de
+
Jakub Jelen def1de
 /* Check that the OID in a data stream matches that in the context */
Jakub Jelen def1de
 int
Jakub Jelen def1de
 ssh_gssapi_check_oid(Gssctxt *ctx, void *data, size_t len)
Jakub Jelen 51f5c1
@@ -218,7 +398,7 @@ ssh_gssapi_init_ctx(Gssctxt *ctx, int deleg_creds, gss_buffer_desc *recv_tok,
Jakub Jelen def1de
 	}
Jakub Jelen def1de
 
Jakub Jelen def1de
 	ctx->major = gss_init_sec_context(&ctx->minor,
Jakub Jelen def1de
-	    GSS_C_NO_CREDENTIAL, &ctx->context, ctx->name, ctx->oid,
Jakub Jelen def1de
+	    ctx->client_creds, &ctx->context, ctx->name, ctx->oid,
Jakub Jelen def1de
 	    GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG | deleg_flag,
Jakub Jelen def1de
 	    0, NULL, recv_tok, NULL, send_tok, flags, NULL);
Jakub Jelen def1de
 
Jakub Jelen 51f5c1
@@ -247,9 +427,43 @@ ssh_gssapi_import_name(Gssctxt *ctx, const char *host)
Jakub Jelen def1de
 	return (ctx->major);
Jakub Jelen def1de
 }
Jakub Jelen def1de
 
Jakub Jelen def1de
+OM_uint32
Jakub Jelen def1de
+ssh_gssapi_client_identity(Gssctxt *ctx, const char *name)
Jakub Jelen def1de
+{
Jakub Jelen def1de
+	gss_buffer_desc gssbuf;
Jakub Jelen def1de
+	gss_name_t gssname;
Jakub Jelen def1de
+	OM_uint32 status;
Jakub Jelen def1de
+	gss_OID_set oidset;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	gssbuf.value = (void *) name;
Jakub Jelen def1de
+	gssbuf.length = strlen(gssbuf.value);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	gss_create_empty_oid_set(&status, &oidset);
Jakub Jelen def1de
+	gss_add_oid_set_member(&status, ctx->oid, &oidset);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	ctx->major = gss_import_name(&ctx->minor, &gssbuf,
Jakub Jelen def1de
+	    GSS_C_NT_USER_NAME, &gssname);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if (!ctx->major)
Jakub Jelen def1de
+		ctx->major = gss_acquire_cred(&ctx->minor,
Jakub Jelen def1de
+		    gssname, 0, oidset, GSS_C_INITIATE,
Jakub Jelen def1de
+		    &ctx->client_creds, NULL, NULL);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	gss_release_name(&status, &gssname);
Jakub Jelen def1de
+	gss_release_oid_set(&status, &oidset);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if (ctx->major)
Jakub Jelen def1de
+		ssh_gssapi_error(ctx);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	return(ctx->major);
Jakub Jelen def1de
+}
Jakub Jelen def1de
+
Jakub Jelen def1de
 OM_uint32
Jakub Jelen def1de
 ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash)
Jakub Jelen def1de
 {
Jakub Jelen def1de
+	if (ctx == NULL)
Jakub Jelen def1de
+		return -1;
Jakub Jelen def1de
+
Jakub Jelen def1de
 	if ((ctx->major = gss_get_mic(&ctx->minor, ctx->context,
Jakub Jelen def1de
 	    GSS_C_QOP_DEFAULT, buffer, hash)))
Jakub Jelen def1de
 		ssh_gssapi_error(ctx);
Jakub Jelen 51f5c1
@@ -257,6 +471,19 @@ ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash)
Jakub Jelen def1de
 	return (ctx->major);
Jakub Jelen def1de
 }
Jakub Jelen def1de
 
Jakub Jelen def1de
+/* Priviledged when used by server */
Jakub Jelen def1de
+OM_uint32
Jakub Jelen def1de
+ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic)
Jakub Jelen def1de
+{
Jakub Jelen def1de
+	if (ctx == NULL)
Jakub Jelen def1de
+		return -1;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	ctx->major = gss_verify_mic(&ctx->minor, ctx->context,
Jakub Jelen def1de
+	    gssbuf, gssmic, NULL);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	return (ctx->major);
Jakub Jelen def1de
+}
Jakub Jelen def1de
+
Jakub Jelen def1de
 void
Jakub Jelen def1de
 ssh_gssapi_buildmic(struct sshbuf *b, const char *user, const char *service,
Jakub Jelen def1de
     const char *context)
Jakub Jelen 51f5c1
@@ -273,11 +500,16 @@ ssh_gssapi_buildmic(struct sshbuf *b, const char *user, const char *service,
Jakub Jelen def1de
 }
Jakub Jelen def1de
 
Jakub Jelen def1de
 int
Jakub Jelen def1de
-ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host)
Jakub Jelen def1de
+ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host,
Jakub Jelen def1de
+    const char *client)
Jakub Jelen def1de
 {
Jakub Jelen def1de
 	gss_buffer_desc token = GSS_C_EMPTY_BUFFER;
Jakub Jelen def1de
 	OM_uint32 major, minor;
Jakub Jelen def1de
 	gss_OID_desc spnego_oid = {6, (void *)"\x2B\x06\x01\x05\x05\x02"};
Jakub Jelen def1de
+	Gssctxt *intctx = NULL;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if (ctx == NULL)
Jakub Jelen def1de
+		ctx = &intct;;
Jakub Jelen def1de
 
Jakub Jelen def1de
 	/* RFC 4462 says we MUST NOT do SPNEGO */
Jakub Jelen def1de
 	if (oid->length == spnego_oid.length && 
Jakub Jelen 51f5c1
@@ -287,6 +519,10 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host)
Jakub Jelen def1de
 	ssh_gssapi_build_ctx(ctx);
Jakub Jelen def1de
 	ssh_gssapi_set_oid(*ctx, oid);
Jakub Jelen def1de
 	major = ssh_gssapi_import_name(*ctx, host);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if (!GSS_ERROR(major) && client)
Jakub Jelen def1de
+		major = ssh_gssapi_client_identity(*ctx, client);
Jakub Jelen def1de
+
Jakub Jelen def1de
 	if (!GSS_ERROR(major)) {
Jakub Jelen def1de
 		major = ssh_gssapi_init_ctx(*ctx, 0, GSS_C_NO_BUFFER, &token, 
Jakub Jelen def1de
 		    NULL);
Jakub Jelen 51f5c1
@@ -296,10 +532,66 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host)
Jakub Jelen def1de
 			    GSS_C_NO_BUFFER);
Jakub Jelen def1de
 	}
Jakub Jelen def1de
 
Jakub Jelen def1de
-	if (GSS_ERROR(major)) 
Jakub Jelen def1de
+	if (GSS_ERROR(major) || intctx != NULL)
Jakub Jelen def1de
 		ssh_gssapi_delete_ctx(ctx);
Jakub Jelen def1de
 
Jakub Jelen def1de
 	return (!GSS_ERROR(major));
Jakub Jelen def1de
 }
Jakub Jelen def1de
 
Jakub Jelen def1de
+int
Jakub Jelen def1de
+ssh_gssapi_credentials_updated(Gssctxt *ctxt) {
Jakub Jelen def1de
+	static gss_name_t saved_name = GSS_C_NO_NAME;
Jakub Jelen def1de
+	static OM_uint32 saved_lifetime = 0;
Jakub Jelen def1de
+	static gss_OID saved_mech = GSS_C_NO_OID;
Jakub Jelen def1de
+	static gss_name_t name;
Jakub Jelen def1de
+	static OM_uint32 last_call = 0;
Jakub Jelen def1de
+	OM_uint32 lifetime, now, major, minor;
Jakub Jelen def1de
+	int equal;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	now = time(NULL);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if (ctxt) {
Jakub Jelen def1de
+		debug("Rekey has happened - updating saved versions");
Jakub Jelen def1de
+
Jakub Jelen def1de
+		if (saved_name != GSS_C_NO_NAME)
Jakub Jelen def1de
+			gss_release_name(&minor, &saved_name);
Jakub Jelen def1de
+
Jakub Jelen def1de
+		major = gss_inquire_cred(&minor, GSS_C_NO_CREDENTIAL,
Jakub Jelen def1de
+		    &saved_name, &saved_lifetime, NULL, NULL);
Jakub Jelen def1de
+
Jakub Jelen def1de
+		if (!GSS_ERROR(major)) {
Jakub Jelen def1de
+			saved_mech = ctxt->oid;
Jakub Jelen def1de
+		        saved_lifetime+= now;
Jakub Jelen def1de
+		} else {
Jakub Jelen def1de
+			/* Handle the error */
Jakub Jelen def1de
+		}
Jakub Jelen def1de
+		return 0;
Jakub Jelen def1de
+	}
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if (now - last_call < 10)
Jakub Jelen def1de
+		return 0;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	last_call = now;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if (saved_mech == GSS_C_NO_OID)
Jakub Jelen def1de
+		return 0;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	major = gss_inquire_cred(&minor, GSS_C_NO_CREDENTIAL,
Jakub Jelen def1de
+	    &name, &lifetime, NULL, NULL);
Jakub Jelen def1de
+	if (major == GSS_S_CREDENTIALS_EXPIRED)
Jakub Jelen def1de
+		return 0;
Jakub Jelen def1de
+	else if (GSS_ERROR(major))
Jakub Jelen def1de
+		return 0;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	major = gss_compare_name(&minor, saved_name, name, &equal);
Jakub Jelen def1de
+	gss_release_name(&minor, &name);
Jakub Jelen def1de
+	if (GSS_ERROR(major))
Jakub Jelen def1de
+		return 0;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if (equal && (saved_lifetime < lifetime + now - 10))
Jakub Jelen def1de
+		return 1;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	return 0;
Jakub Jelen def1de
+}
Jakub Jelen def1de
+
Jakub Jelen def1de
 #endif /* GSSAPI */
Jakub Jelen def1de
diff --git a/gss-serv-krb5.c b/gss-serv-krb5.c
Jakub Jelen def1de
index a151bc1e..8d2b677f 100644
Jakub Jelen def1de
--- a/gss-serv-krb5.c
Jakub Jelen def1de
+++ b/gss-serv-krb5.c
Jakub Jelen def1de
@@ -1,7 +1,7 @@
Jakub Jelen def1de
 /* $OpenBSD: gss-serv-krb5.c,v 1.9 2018/07/09 21:37:55 markus Exp $ */
Jakub Jelen def1de
 
Jakub Jelen def1de
 /*
Jakub Jelen def1de
- * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
Jakub Jelen def1de
+ * Copyright (c) 2001-2007 Simon Wilkinson. All rights reserved.
Jakub Jelen def1de
  *
Jakub Jelen def1de
  * Redistribution and use in source and binary forms, with or without
Jakub Jelen def1de
  * modification, are permitted provided that the following conditions
Jakub Jelen def1de
@@ -120,7 +120,7 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client)
Jakub Jelen def1de
 	krb5_error_code problem;
Jakub Jelen def1de
 	krb5_principal princ;
Jakub Jelen def1de
 	OM_uint32 maj_status, min_status;
Jakub Jelen def1de
-	int len;
Jakub Jelen def1de
+	const char *new_ccname, *new_cctype;
Jakub Jelen def1de
 	const char *errmsg;
Jakub Jelen def1de
 
Jakub Jelen def1de
 	if (client->creds == NULL) {
Jakub Jelen def1de
@@ -180,11 +180,26 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client)
Jakub Jelen def1de
 		return;
Jakub Jelen def1de
 	}
Jakub Jelen def1de
 
Jakub Jelen def1de
-	client->store.filename = xstrdup(krb5_cc_get_name(krb_context, ccache));
Jakub Jelen def1de
+	new_cctype = krb5_cc_get_type(krb_context, ccache);
Jakub Jelen def1de
+	new_ccname = krb5_cc_get_name(krb_context, ccache);
Jakub Jelen def1de
+
Jakub Jelen def1de
 	client->store.envvar = "KRB5CCNAME";
Jakub Jelen def1de
-	len = strlen(client->store.filename) + 6;
Jakub Jelen def1de
-	client->store.envval = xmalloc(len);
Jakub Jelen def1de
-	snprintf(client->store.envval, len, "FILE:%s", client->store.filename);
Jakub Jelen def1de
+#ifdef USE_CCAPI
Jakub Jelen def1de
+	xasprintf(&client->store.envval, "API:%s", new_ccname);
Jakub Jelen def1de
+	client->store.filename = NULL;
Jakub Jelen def1de
+#else
Jakub Jelen def1de
+	if (new_ccname[0] == ':')
Jakub Jelen def1de
+		new_ccname++;
Jakub Jelen def1de
+	xasprintf(&client->store.envval, "%s:%s", new_cctype, new_ccname);
Jakub Jelen def1de
+	if (strcmp(new_cctype, "DIR") == 0) {
Jakub Jelen def1de
+		char *p;
Jakub Jelen def1de
+		p = strrchr(client->store.envval, '/');
Jakub Jelen def1de
+		if (p)
Jakub Jelen def1de
+			*p = '\0';
Jakub Jelen def1de
+	}
Jakub Jelen def1de
+	if ((strcmp(new_cctype, "FILE") == 0) || (strcmp(new_cctype, "DIR") == 0))
Jakub Jelen def1de
+		client->store.filename = xstrdup(new_ccname);
Jakub Jelen def1de
+#endif
Jakub Jelen def1de
 
Jakub Jelen def1de
 #ifdef USE_PAM
Jakub Jelen def1de
 	if (options.use_pam)
Jakub Jelen def1de
@@ -193,9 +208,76 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client)
Jakub Jelen def1de
 
Jakub Jelen def1de
 	krb5_cc_close(krb_context, ccache);
Jakub Jelen def1de
 
Jakub Jelen def1de
+	client->store.data = krb_context;
Jakub Jelen def1de
+
Jakub Jelen def1de
 	return;
Jakub Jelen def1de
 }
Jakub Jelen def1de
 
Jakub Jelen def1de
+int
Jakub Jelen def1de
+ssh_gssapi_krb5_updatecreds(ssh_gssapi_ccache *store,
Jakub Jelen def1de
+    ssh_gssapi_client *client)
Jakub Jelen def1de
+{
Jakub Jelen def1de
+	krb5_ccache ccache = NULL;
Jakub Jelen def1de
+	krb5_principal principal = NULL;
Jakub Jelen def1de
+	char *name = NULL;
Jakub Jelen def1de
+	krb5_error_code problem;
Jakub Jelen def1de
+	OM_uint32 maj_status, min_status;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if ((problem = krb5_cc_resolve(krb_context, store->envval, &ccache))) {
Jakub Jelen def1de
+                logit("krb5_cc_resolve(): %.100s",
Jakub Jelen def1de
+                    krb5_get_err_text(krb_context, problem));
Jakub Jelen def1de
+                return 0;
Jakub Jelen def1de
+	}
Jakub Jelen def1de
+
Jakub Jelen def1de
+	/* Find out who the principal in this cache is */
Jakub Jelen def1de
+	if ((problem = krb5_cc_get_principal(krb_context, ccache,
Jakub Jelen def1de
+	    &principal))) {
Jakub Jelen def1de
+		logit("krb5_cc_get_principal(): %.100s",
Jakub Jelen def1de
+		    krb5_get_err_text(krb_context, problem));
Jakub Jelen def1de
+		krb5_cc_close(krb_context, ccache);
Jakub Jelen def1de
+		return 0;
Jakub Jelen def1de
+	}
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if ((problem = krb5_unparse_name(krb_context, principal, &name))) {
Jakub Jelen def1de
+		logit("krb5_unparse_name(): %.100s",
Jakub Jelen def1de
+		    krb5_get_err_text(krb_context, problem));
Jakub Jelen def1de
+		krb5_free_principal(krb_context, principal);
Jakub Jelen def1de
+		krb5_cc_close(krb_context, ccache);
Jakub Jelen def1de
+		return 0;
Jakub Jelen def1de
+	}
Jakub Jelen def1de
+
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if (strcmp(name,client->exportedname.value)!=0) {
Jakub Jelen def1de
+		debug("Name in local credentials cache differs. Not storing");
Jakub Jelen def1de
+		krb5_free_principal(krb_context, principal);
Jakub Jelen def1de
+		krb5_cc_close(krb_context, ccache);
Jakub Jelen def1de
+		krb5_free_unparsed_name(krb_context, name);
Jakub Jelen def1de
+		return 0;
Jakub Jelen def1de
+	}
Jakub Jelen def1de
+	krb5_free_unparsed_name(krb_context, name);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	/* Name matches, so lets get on with it! */
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if ((problem = krb5_cc_initialize(krb_context, ccache, principal))) {
Jakub Jelen def1de
+		logit("krb5_cc_initialize(): %.100s",
Jakub Jelen def1de
+		    krb5_get_err_text(krb_context, problem));
Jakub Jelen def1de
+		krb5_free_principal(krb_context, principal);
Jakub Jelen def1de
+		krb5_cc_close(krb_context, ccache);
Jakub Jelen def1de
+		return 0;
Jakub Jelen def1de
+	}
Jakub Jelen def1de
+
Jakub Jelen def1de
+	krb5_free_principal(krb_context, principal);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if ((maj_status = gss_krb5_copy_ccache(&min_status, client->creds,
Jakub Jelen def1de
+	    ccache))) {
Jakub Jelen def1de
+		logit("gss_krb5_copy_ccache() failed. Sorry!");
Jakub Jelen def1de
+		krb5_cc_close(krb_context, ccache);
Jakub Jelen def1de
+		return 0;
Jakub Jelen def1de
+	}
Jakub Jelen def1de
+
Jakub Jelen def1de
+	return 1;
Jakub Jelen def1de
+}
Jakub Jelen def1de
+
Jakub Jelen def1de
 ssh_gssapi_mech gssapi_kerberos_mech = {
Jakub Jelen def1de
 	"toWM5Slw5Ew8Mqkay+al2g==",
Jakub Jelen def1de
 	"Kerberos",
Jakub Jelen def1de
@@ -203,7 +285,8 @@ ssh_gssapi_mech gssapi_kerberos_mech = {
Jakub Jelen def1de
 	NULL,
Jakub Jelen def1de
 	&ssh_gssapi_krb5_userok,
Jakub Jelen def1de
 	NULL,
Jakub Jelen def1de
-	&ssh_gssapi_krb5_storecreds
Jakub Jelen def1de
+	&ssh_gssapi_krb5_storecreds,
Jakub Jelen def1de
+	&ssh_gssapi_krb5_updatecreds
Jakub Jelen def1de
 };
Jakub Jelen def1de
 
Jakub Jelen def1de
 #endif /* KRB5 */
Jakub Jelen def1de
diff --git a/gss-serv.c b/gss-serv.c
Jakub Jelen def1de
index ab3a15f0..6ce56e92 100644
Jakub Jelen def1de
--- a/gss-serv.c
Jakub Jelen def1de
+++ b/gss-serv.c
Jakub Jelen def1de
@@ -1,7 +1,7 @@
Jakub Jelen 5cd955
 /* $OpenBSD: gss-serv.c,v 1.32 2020/03/13 03:17:07 djm Exp $ */
Jakub Jelen def1de
 
Jakub Jelen def1de
 /*
Jakub Jelen def1de
- * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
Jakub Jelen def1de
+ * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved.
Jakub Jelen def1de
  *
Jakub Jelen def1de
  * Redistribution and use in source and binary forms, with or without
Jakub Jelen def1de
  * modification, are permitted provided that the following conditions
Jakub Jelen def1de
@@ -44,17 +44,19 @@
Jakub Jelen def1de
 #include "session.h"
Jakub Jelen def1de
 #include "misc.h"
Jakub Jelen def1de
 #include "servconf.h"
Jakub Jelen def1de
+#include "uidswap.h"
Jakub Jelen def1de
 
Jakub Jelen def1de
 #include "ssh-gss.h"
Jakub Jelen def1de
+#include "monitor_wrap.h"
Jakub Jelen def1de
 
Jakub Jelen def1de
 extern ServerOptions options;
Jakub Jelen def1de
 
Jakub Jelen def1de
 static ssh_gssapi_client gssapi_client =
Jakub Jelen def1de
-    { GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER,
Jakub Jelen def1de
-    GSS_C_NO_CREDENTIAL, NULL, {NULL, NULL, NULL, NULL}};
Jakub Jelen def1de
+    { GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER, GSS_C_NO_CREDENTIAL,
Jakub Jelen def1de
+    GSS_C_NO_NAME, NULL, {NULL, NULL, NULL, NULL, NULL}, 0, 0};
Jakub Jelen def1de
 
Jakub Jelen def1de
 ssh_gssapi_mech gssapi_null_mech =
Jakub Jelen def1de
-    { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL};
Jakub Jelen def1de
+    { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL, NULL};
Jakub Jelen def1de
 
Jakub Jelen def1de
 #ifdef KRB5
Jakub Jelen def1de
 extern ssh_gssapi_mech gssapi_kerberos_mech;
Jakub Jelen def1de
@@ -140,6 +142,29 @@ ssh_gssapi_server_ctx(Gssctxt **ctx, gss_OID oid)
Jakub Jelen def1de
 	return (ssh_gssapi_acquire_cred(*ctx));
Jakub Jelen def1de
 }
Jakub Jelen def1de
 
Jakub Jelen def1de
+/* Unprivileged */
Jakub Jelen def1de
+char *
Jakub Jelen def1de
+ssh_gssapi_server_mechanisms(void) {
Jakub Jelen def1de
+	if (supported_oids == NULL)
Jakub Jelen def1de
+		ssh_gssapi_prepare_supported_oids();
Jakub Jelen def1de
+	return (ssh_gssapi_kex_mechs(supported_oids,
Jakub Jelen def1de
+	    &ssh_gssapi_server_check_mech, NULL, NULL,
Jakub Jelen def1de
+	    options.gss_kex_algorithms));
Jakub Jelen def1de
+}
Jakub Jelen def1de
+
Jakub Jelen def1de
+/* Unprivileged */
Jakub Jelen def1de
+int
Jakub Jelen def1de
+ssh_gssapi_server_check_mech(Gssctxt **dum, gss_OID oid, const char *data,
Jakub Jelen def1de
+    const char *dummy) {
Jakub Jelen def1de
+	Gssctxt *ctx = NULL;
Jakub Jelen def1de
+	int res;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	res = !GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctx, oid)));
Jakub Jelen def1de
+	ssh_gssapi_delete_ctx(&ctx;;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	return (res);
Jakub Jelen def1de
+}
Jakub Jelen def1de
+
Jakub Jelen def1de
 /* Unprivileged */
Jakub Jelen def1de
 void
Jakub Jelen def1de
 ssh_gssapi_supported_oids(gss_OID_set *oidset)
Jakub Jelen def1de
@@ -150,7 +175,9 @@ ssh_gssapi_supported_oids(gss_OID_set *oidset)
Jakub Jelen def1de
 	gss_OID_set supported;
Jakub Jelen def1de
 
Jakub Jelen def1de
 	gss_create_empty_oid_set(&min_status, oidset);
Jakub Jelen def1de
-	gss_indicate_mechs(&min_status, &supported);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if (GSS_ERROR(gss_indicate_mechs(&min_status, &supported)))
Jakub Jelen def1de
+		return;
Jakub Jelen def1de
 
Jakub Jelen def1de
 	while (supported_mechs[i]->name != NULL) {
Jakub Jelen def1de
 		if (GSS_ERROR(gss_test_oid_set_member(&min_status,
Jakub Jelen def1de
@@ -276,8 +303,48 @@ OM_uint32
Jakub Jelen def1de
 ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client)
Jakub Jelen def1de
 {
Jakub Jelen def1de
 	int i = 0;
Jakub Jelen def1de
+	int equal = 0;
Jakub Jelen def1de
+	gss_name_t new_name = GSS_C_NO_NAME;
Jakub Jelen def1de
+	gss_buffer_desc ename = GSS_C_EMPTY_BUFFER;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if (options.gss_store_rekey && client->used && ctx->client_creds) {
Jakub Jelen def1de
+		if (client->mech->oid.length != ctx->oid->length ||
Jakub Jelen def1de
+		    (memcmp(client->mech->oid.elements,
Jakub Jelen def1de
+		     ctx->oid->elements, ctx->oid->length) !=0)) {
Jakub Jelen def1de
+			debug("Rekeyed credentials have different mechanism");
Jakub Jelen def1de
+			return GSS_S_COMPLETE;
Jakub Jelen def1de
+		}
Jakub Jelen def1de
+
Jakub Jelen def1de
+		if ((ctx->major = gss_inquire_cred_by_mech(&ctx->minor,
Jakub Jelen def1de
+		    ctx->client_creds, ctx->oid, &new_name,
Jakub Jelen def1de
+		    NULL, NULL, NULL))) {
Jakub Jelen def1de
+			ssh_gssapi_error(ctx);
Jakub Jelen def1de
+			return (ctx->major);
Jakub Jelen def1de
+		}
Jakub Jelen def1de
 
Jakub Jelen def1de
-	gss_buffer_desc ename;
Jakub Jelen def1de
+		ctx->major = gss_compare_name(&ctx->minor, client->name,
Jakub Jelen def1de
+		    new_name, &equal);
Jakub Jelen def1de
+
Jakub Jelen def1de
+		if (GSS_ERROR(ctx->major)) {
Jakub Jelen def1de
+			ssh_gssapi_error(ctx);
Jakub Jelen def1de
+			return (ctx->major);
Jakub Jelen def1de
+		}
Jakub Jelen def1de
+
Jakub Jelen def1de
+		if (!equal) {
Jakub Jelen def1de
+			debug("Rekeyed credentials have different name");
Jakub Jelen def1de
+			return GSS_S_COMPLETE;
Jakub Jelen def1de
+		}
Jakub Jelen def1de
+
Jakub Jelen def1de
+		debug("Marking rekeyed credentials for export");
Jakub Jelen def1de
+
Jakub Jelen def1de
+		gss_release_name(&ctx->minor, &client->name);
Jakub Jelen def1de
+		gss_release_cred(&ctx->minor, &client->creds);
Jakub Jelen def1de
+		client->name = new_name;
Jakub Jelen def1de
+		client->creds = ctx->client_creds;
Jakub Jelen def1de
+		ctx->client_creds = GSS_C_NO_CREDENTIAL;
Jakub Jelen def1de
+		client->updated = 1;
Jakub Jelen def1de
+		return GSS_S_COMPLETE;
Jakub Jelen def1de
+	}
Jakub Jelen def1de
 
Jakub Jelen def1de
 	client->mech = NULL;
Jakub Jelen def1de
 
Jakub Jelen def1de
@@ -292,6 +359,13 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client)
Jakub Jelen def1de
 	if (client->mech == NULL)
Jakub Jelen def1de
 		return GSS_S_FAILURE;
Jakub Jelen def1de
 
Jakub Jelen def1de
+	if (ctx->client_creds &&
Jakub Jelen def1de
+	    (ctx->major = gss_inquire_cred_by_mech(&ctx->minor,
Jakub Jelen def1de
+	     ctx->client_creds, ctx->oid, &client->name, NULL, NULL, NULL))) {
Jakub Jelen def1de
+		ssh_gssapi_error(ctx);
Jakub Jelen def1de
+		return (ctx->major);
Jakub Jelen def1de
+	}
Jakub Jelen def1de
+
Jakub Jelen def1de
 	if ((ctx->major = gss_display_name(&ctx->minor, ctx->client,
Jakub Jelen def1de
 	    &client->displayname, NULL))) {
Jakub Jelen def1de
 		ssh_gssapi_error(ctx);
Jakub Jelen def1de
@@ -309,6 +383,8 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client)
Jakub Jelen def1de
 		return (ctx->major);
Jakub Jelen def1de
 	}
Jakub Jelen def1de
 
Jakub Jelen def1de
+	gss_release_buffer(&ctx->minor, &ename);
Jakub Jelen def1de
+
Jakub Jelen def1de
 	/* We can't copy this structure, so we just move the pointer to it */
Jakub Jelen def1de
 	client->creds = ctx->client_creds;
Jakub Jelen def1de
 	ctx->client_creds = GSS_C_NO_CREDENTIAL;
Jakub Jelen def1de
@@ -319,11 +395,20 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client)
Jakub Jelen def1de
 void
Jakub Jelen def1de
 ssh_gssapi_cleanup_creds(void)
Jakub Jelen def1de
 {
Jakub Jelen def1de
-	if (gssapi_client.store.filename != NULL) {
Jakub Jelen def1de
-		/* Unlink probably isn't sufficient */
Jakub Jelen def1de
-		debug("removing gssapi cred file\"%s\"",
Jakub Jelen def1de
-		    gssapi_client.store.filename);
Jakub Jelen def1de
-		unlink(gssapi_client.store.filename);
Jakub Jelen def1de
+	krb5_ccache ccache = NULL;
Jakub Jelen def1de
+	krb5_error_code problem;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if (gssapi_client.store.data != NULL) {
Jakub Jelen def1de
+		if ((problem = krb5_cc_resolve(gssapi_client.store.data, gssapi_client.store.envval, &ccache))) {
Jakub Jelen def1de
+			debug("%s: krb5_cc_resolve(): %.100s", __func__,
Jakub Jelen def1de
+				krb5_get_err_text(gssapi_client.store.data, problem));
Jakub Jelen def1de
+		} else if ((problem = krb5_cc_destroy(gssapi_client.store.data, ccache))) {
Jakub Jelen def1de
+			debug("%s: krb5_cc_destroy(): %.100s", __func__,
Jakub Jelen def1de
+				krb5_get_err_text(gssapi_client.store.data, problem));
Jakub Jelen def1de
+		} else {
Jakub Jelen def1de
+			krb5_free_context(gssapi_client.store.data);
Jakub Jelen def1de
+			gssapi_client.store.data = NULL;
Jakub Jelen def1de
+		}
Jakub Jelen def1de
 	}
Jakub Jelen def1de
 }
Jakub Jelen def1de
 
Jakub Jelen def1de
@@ -356,19 +441,23 @@ ssh_gssapi_do_child(char ***envp, u_int *envsizep)
Jakub Jelen def1de
 
Jakub Jelen def1de
 /* Privileged */
Jakub Jelen def1de
 int
Jakub Jelen def1de
-ssh_gssapi_userok(char *user)
Jakub Jelen def1de
+ssh_gssapi_userok(char *user, struct passwd *pw, int kex)
Jakub Jelen def1de
 {
Jakub Jelen def1de
 	OM_uint32 lmin;
Jakub Jelen def1de
 
Jakub Jelen def1de
+	(void) kex; /* used in privilege separation */
Jakub Jelen def1de
+
Jakub Jelen def1de
 	if (gssapi_client.exportedname.length == 0 ||
Jakub Jelen def1de
 	    gssapi_client.exportedname.value == NULL) {
Jakub Jelen def1de
 		debug("No suitable client data");
Jakub Jelen def1de
 		return 0;
Jakub Jelen def1de
 	}
Jakub Jelen def1de
 	if (gssapi_client.mech && gssapi_client.mech->userok)
Jakub Jelen def1de
-		if ((*gssapi_client.mech->userok)(&gssapi_client, user))
Jakub Jelen def1de
+		if ((*gssapi_client.mech->userok)(&gssapi_client, user)) {
Jakub Jelen def1de
+			gssapi_client.used = 1;
Jakub Jelen def1de
+			gssapi_client.store.owner = pw;
Jakub Jelen def1de
 			return 1;
Jakub Jelen def1de
-		else {
Jakub Jelen def1de
+		} else {
Jakub Jelen def1de
 			/* Destroy delegated credentials if userok fails */
Jakub Jelen def1de
 			gss_release_buffer(&lmin, &gssapi_client.displayname);
Jakub Jelen def1de
 			gss_release_buffer(&lmin, &gssapi_client.exportedname);
Jakub Jelen def1de
@@ -382,14 +471,90 @@ ssh_gssapi_userok(char *user)
Jakub Jelen def1de
 	return (0);
Jakub Jelen def1de
 }
Jakub Jelen def1de
 
Jakub Jelen def1de
-/* Privileged */
Jakub Jelen def1de
-OM_uint32
Jakub Jelen def1de
-ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic)
Jakub Jelen def1de
+/* These bits are only used for rekeying. The unpriviledged child is running
Jakub Jelen def1de
+ * as the user, the monitor is root.
Jakub Jelen def1de
+ *
Jakub Jelen def1de
+ * In the child, we want to :
Jakub Jelen def1de
+ *    *) Ask the monitor to store our credentials into the store we specify
Jakub Jelen def1de
+ *    *) If it succeeds, maybe do a PAM update
Jakub Jelen def1de
+ */
Jakub Jelen def1de
+
Jakub Jelen def1de
+/* Stuff for PAM */
Jakub Jelen def1de
+
Jakub Jelen def1de
+#ifdef USE_PAM
Jakub Jelen def1de
+static int ssh_gssapi_simple_conv(int n, const struct pam_message **msg,
Jakub Jelen def1de
+    struct pam_response **resp, void *data)
Jakub Jelen def1de
 {
Jakub Jelen def1de
-	ctx->major = gss_verify_mic(&ctx->minor, ctx->context,
Jakub Jelen def1de
-	    gssbuf, gssmic, NULL);
Jakub Jelen def1de
+	return (PAM_CONV_ERR);
Jakub Jelen def1de
+}
Jakub Jelen def1de
+#endif
Jakub Jelen def1de
 
Jakub Jelen def1de
-	return (ctx->major);
Jakub Jelen def1de
+void
Jakub Jelen def1de
+ssh_gssapi_rekey_creds(void) {
Jakub Jelen def1de
+	int ok;
Jakub Jelen def1de
+#ifdef USE_PAM
Jakub Jelen def1de
+	int ret;
Jakub Jelen def1de
+	pam_handle_t *pamh = NULL;
Jakub Jelen def1de
+	struct pam_conv pamconv = {ssh_gssapi_simple_conv, NULL};
Jakub Jelen def1de
+	char *envstr;
Jakub Jelen def1de
+#endif
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if (gssapi_client.store.filename == NULL &&
Jakub Jelen def1de
+	    gssapi_client.store.envval == NULL &&
Jakub Jelen def1de
+	    gssapi_client.store.envvar == NULL)
Jakub Jelen def1de
+		return;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	ok = PRIVSEP(ssh_gssapi_update_creds(&gssapi_client.store));
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if (!ok)
Jakub Jelen def1de
+		return;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	debug("Rekeyed credentials stored successfully");
Jakub Jelen def1de
+
Jakub Jelen def1de
+	/* Actually managing to play with the ssh pam stack from here will
Jakub Jelen def1de
+	 * be next to impossible. In any case, we may want different options
Jakub Jelen def1de
+	 * for rekeying. So, use our own :)
Jakub Jelen def1de
+	 */
Jakub Jelen def1de
+#ifdef USE_PAM	
Jakub Jelen def1de
+	if (!use_privsep) {
Jakub Jelen def1de
+		debug("Not even going to try and do PAM with privsep disabled");
Jakub Jelen def1de
+		return;
Jakub Jelen def1de
+	}
Jakub Jelen def1de
+
Jakub Jelen def1de
+	ret = pam_start("sshd-rekey", gssapi_client.store.owner->pw_name,
Jakub Jelen def1de
+ 	    &pamconv, &pamh);
Jakub Jelen def1de
+	if (ret)
Jakub Jelen def1de
+		return;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	xasprintf(&envstr, "%s=%s", gssapi_client.store.envvar,
Jakub Jelen def1de
+	    gssapi_client.store.envval);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	ret = pam_putenv(pamh, envstr);
Jakub Jelen def1de
+	if (!ret)
Jakub Jelen def1de
+		pam_setcred(pamh, PAM_REINITIALIZE_CRED);
Jakub Jelen def1de
+	pam_end(pamh, PAM_SUCCESS);
Jakub Jelen def1de
+#endif
Jakub Jelen def1de
+}
Jakub Jelen def1de
+
Jakub Jelen def1de
+int
Jakub Jelen def1de
+ssh_gssapi_update_creds(ssh_gssapi_ccache *store) {
Jakub Jelen def1de
+	int ok = 0;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	/* Check we've got credentials to store */
Jakub Jelen def1de
+	if (!gssapi_client.updated)
Jakub Jelen def1de
+		return 0;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	gssapi_client.updated = 0;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	temporarily_use_uid(gssapi_client.store.owner);
Jakub Jelen def1de
+	if (gssapi_client.mech && gssapi_client.mech->updatecreds)
Jakub Jelen def1de
+		ok = (*gssapi_client.mech->updatecreds)(store, &gssapi_client);
Jakub Jelen def1de
+	else
Jakub Jelen def1de
+		debug("No update function for this mechanism");
Jakub Jelen def1de
+
Jakub Jelen def1de
+	restore_uid();
Jakub Jelen def1de
+
Jakub Jelen def1de
+	return ok;
Jakub Jelen def1de
 }
Jakub Jelen def1de
 
Jakub Jelen def1de
 /* Privileged */
Jakub Jelen def1de
diff --git a/kex.c b/kex.c
Jakub Jelen 51f5c1
index ce85f043..574c7609 100644
Jakub Jelen def1de
--- a/kex.c
Jakub Jelen def1de
+++ b/kex.c
Jakub Jelen 51f5c1
@@ -57,11 +57,16 @@
Jakub Jelen def1de
 #include "misc.h"
Jakub Jelen def1de
 #include "dispatch.h"
Jakub Jelen def1de
 #include "monitor.h"
Jakub Jelen def1de
+#include "xmalloc.h"
Jakub Jelen def1de
 
Jakub Jelen def1de
 #include "ssherr.h"
Jakub Jelen def1de
 #include "sshbuf.h"
Jakub Jelen def1de
 #include "digest.h"
Jakub Jelen def1de
 
Jakub Jelen def1de
+#ifdef GSSAPI
Jakub Jelen def1de
+#include "ssh-gss.h"
Jakub Jelen def1de
+#endif
Jakub Jelen def1de
+
Jakub Jelen def1de
 /* prototype */
Jakub Jelen def1de
 static int kex_choose_conf(struct ssh *);
Jakub Jelen def1de
 static int kex_input_newkeys(int, u_int32_t, struct ssh *);
Jakub Jelen 51f5c1
@@ -115,15 +120,28 @@ static const struct kexalg kexalgs[] = {
Jakub Jelen def1de
 #endif /* HAVE_EVP_SHA256 || !WITH_OPENSSL */
Jakub Jelen 36fef5
 	{ NULL, 0, -1, -1},
Jakub Jelen def1de
 };
Jakub Jelen def1de
+static const struct kexalg gss_kexalgs[] = {
Jakub Jelen def1de
+#ifdef GSSAPI
Jakub Jelen def1de
+	{ KEX_GSS_GEX_SHA1_ID, KEX_GSS_GEX_SHA1, 0, SSH_DIGEST_SHA1 },
Jakub Jelen def1de
+	{ KEX_GSS_GRP1_SHA1_ID, KEX_GSS_GRP1_SHA1, 0, SSH_DIGEST_SHA1 },
Jakub Jelen def1de
+	{ KEX_GSS_GRP14_SHA1_ID, KEX_GSS_GRP14_SHA1, 0, SSH_DIGEST_SHA1 },
Jakub Jelen def1de
+	{ KEX_GSS_GRP14_SHA256_ID, KEX_GSS_GRP14_SHA256, 0, SSH_DIGEST_SHA256 },
Jakub Jelen def1de
+	{ KEX_GSS_GRP16_SHA512_ID, KEX_GSS_GRP16_SHA512, 0, SSH_DIGEST_SHA512 },
Jakub Jelen def1de
+	{ KEX_GSS_NISTP256_SHA256_ID, KEX_GSS_NISTP256_SHA256,
Jakub Jelen def1de
+	    NID_X9_62_prime256v1, SSH_DIGEST_SHA256 },
Jakub Jelen def1de
+	{ KEX_GSS_C25519_SHA256_ID, KEX_GSS_C25519_SHA256, 0, SSH_DIGEST_SHA256 },
Jakub Jelen def1de
+#endif
Jakub Jelen 51f5c1
+	{ NULL, 0, -1, -1},
Jakub Jelen def1de
+};
Jakub Jelen def1de
 
Jakub Jelen def1de
-char *
Jakub Jelen def1de
-kex_alg_list(char sep)
Jakub Jelen def1de
+static char *
Jakub Jelen def1de
+kex_alg_list_internal(char sep, const struct kexalg *algs)
Jakub Jelen def1de
 {
Jakub Jelen def1de
 	char *ret = NULL, *tmp;
Jakub Jelen def1de
 	size_t nlen, rlen = 0;
Jakub Jelen def1de
 	const struct kexalg *k;
Jakub Jelen def1de
 
Jakub Jelen def1de
-	for (k = kexalgs; k->name != NULL; k++) {
Jakub Jelen def1de
+	for (k = algs; k->name != NULL; k++) {
Jakub Jelen def1de
 		if (ret != NULL)
Jakub Jelen def1de
 			ret[rlen++] = sep;
Jakub Jelen def1de
 		nlen = strlen(k->name);
Jakub Jelen 51f5c1
@@ -138,6 +156,18 @@ kex_alg_list(char sep)
Jakub Jelen def1de
 	return ret;
Jakub Jelen def1de
 }
Jakub Jelen def1de
 
Jakub Jelen def1de
+char *
Jakub Jelen def1de
+kex_alg_list(char sep)
Jakub Jelen def1de
+{
Jakub Jelen def1de
+	return kex_alg_list_internal(sep, kexalgs);
Jakub Jelen def1de
+}
Jakub Jelen def1de
+
Jakub Jelen def1de
+char *
Jakub Jelen def1de
+kex_gss_alg_list(char sep)
Jakub Jelen def1de
+{
Jakub Jelen def1de
+	return kex_alg_list_internal(sep, gss_kexalgs);
Jakub Jelen def1de
+}
Jakub Jelen def1de
+
Jakub Jelen def1de
 static const struct kexalg *
Jakub Jelen def1de
 kex_alg_by_name(const char *name)
Jakub Jelen def1de
 {
Jakub Jelen 51f5c1
@@ -147,6 +177,10 @@ kex_alg_by_name(const char *name)
Jakub Jelen def1de
 		if (strcmp(k->name, name) == 0)
Jakub Jelen def1de
 			return k;
Jakub Jelen def1de
 	}
Jakub Jelen def1de
+	for (k = gss_kexalgs; k->name != NULL; k++) {
Jakub Jelen def1de
+		if (strncmp(k->name, name, strlen(k->name)) == 0)
Jakub Jelen def1de
+			return k;
Jakub Jelen def1de
+	}
Jakub Jelen def1de
 	return NULL;
Jakub Jelen def1de
 }
Jakub Jelen def1de
 
Jakub Jelen 51f5c1
@@ -315,6 +349,29 @@ kex_assemble_names(char **listp, const char *def, const char *all)
Jakub Jelen def1de
 	return r;
Jakub Jelen def1de
 }
Jakub Jelen def1de
 
Jakub Jelen def1de
+/* Validate GSS KEX method name list */
Jakub Jelen def1de
+int
Jakub Jelen def1de
+kex_gss_names_valid(const char *names)
Jakub Jelen def1de
+{
Jakub Jelen def1de
+	char *s, *cp, *p;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if (names == NULL || *names == '\0')
Jakub Jelen def1de
+		return 0;
Jakub Jelen def1de
+	s = cp = xstrdup(names);
Jakub Jelen def1de
+	for ((p = strsep(&cp, ",")); p && *p != '\0';
Jakub Jelen def1de
+	    (p = strsep(&cp, ","))) {
Jakub Jelen def1de
+		if (strncmp(p, "gss-", 4) != 0
Jakub Jelen def1de
+		  || kex_alg_by_name(p) == NULL) {
Jakub Jelen def1de
+			error("Unsupported KEX algorithm \"%.100s\"", p);
Jakub Jelen def1de
+			free(s);
Jakub Jelen def1de
+			return 0;
Jakub Jelen def1de
+		}
Jakub Jelen def1de
+	}
Jakub Jelen def1de
+	debug3("gss kex names ok: [%s]", names);
Jakub Jelen def1de
+	free(s);
Jakub Jelen def1de
+	return 1;
Jakub Jelen def1de
+}
Jakub Jelen def1de
+
Jakub Jelen def1de
 /* put algorithm proposal into buffer */
Jakub Jelen def1de
 int
Jakub Jelen def1de
 kex_prop2buf(struct sshbuf *b, char *proposal[PROPOSAL_MAX])
Jakub Jelen 51f5c1
@@ -698,6 +755,9 @@ kex_free(struct kex *kex)
Jakub Jelen def1de
 	sshbuf_free(kex->server_version);
Jakub Jelen def1de
 	sshbuf_free(kex->client_pub);
Jakub Jelen def1de
 	free(kex->session_id);
Jakub Jelen def1de
+#ifdef GSSAPI
Jakub Jelen def1de
+	free(kex->gss_host);
Jakub Jelen def1de
+#endif /* GSSAPI */
Jakub Jelen def1de
 	free(kex->failed_choice);
Jakub Jelen def1de
 	free(kex->hostkey_alg);
Jakub Jelen def1de
 	free(kex->name);
Jakub Jelen def1de
diff --git a/kex.h b/kex.h
Jakub Jelen 51f5c1
index a5ae6ac0..fe714141 100644
Jakub Jelen def1de
--- a/kex.h
Jakub Jelen def1de
+++ b/kex.h
Jakub Jelen 51f5c1
@@ -102,6 +102,15 @@ enum kex_exchange {
Jakub Jelen def1de
 	KEX_ECDH_SHA2,
Jakub Jelen def1de
 	KEX_C25519_SHA256,
Jakub Jelen def1de
 	KEX_KEM_SNTRUP4591761X25519_SHA512,
Jakub Jelen def1de
+#ifdef GSSAPI
Jakub Jelen def1de
+	KEX_GSS_GRP1_SHA1,
Jakub Jelen def1de
+	KEX_GSS_GRP14_SHA1,
Jakub Jelen def1de
+	KEX_GSS_GRP14_SHA256,
Jakub Jelen def1de
+	KEX_GSS_GRP16_SHA512,
Jakub Jelen def1de
+	KEX_GSS_GEX_SHA1,
Jakub Jelen def1de
+	KEX_GSS_NISTP256_SHA256,
Jakub Jelen def1de
+	KEX_GSS_C25519_SHA256,
Jakub Jelen def1de
+#endif
Jakub Jelen def1de
 	KEX_MAX
Jakub Jelen def1de
 };
Jakub Jelen def1de
 
Jakub Jelen 51f5c1
@@ -153,6 +162,12 @@ struct kex {
Jakub Jelen def1de
 	u_int	flags;
Jakub Jelen def1de
 	int	hash_alg;
Jakub Jelen def1de
 	int	ec_nid;
Jakub Jelen def1de
+#ifdef GSSAPI
Jakub Jelen def1de
+	int	gss_deleg_creds;
Jakub Jelen def1de
+	int	gss_trust_dns;
Jakub Jelen def1de
+	char    *gss_host;
Jakub Jelen def1de
+	char	*gss_client;
Jakub Jelen def1de
+#endif
Jakub Jelen def1de
 	char	*failed_choice;
Jakub Jelen def1de
 	int	(*verify_host_key)(struct sshkey *, struct ssh *);
Jakub Jelen def1de
 	struct sshkey *(*load_host_public_key)(int, int, struct ssh *);
Jakub Jelen 51f5c1
@@ -174,8 +189,10 @@ struct kex {
Jakub Jelen def1de
 
Jakub Jelen def1de
 int	 kex_names_valid(const char *);
Jakub Jelen def1de
 char	*kex_alg_list(char);
Jakub Jelen def1de
+char	*kex_gss_alg_list(char);
Jakub Jelen def1de
 char	*kex_names_cat(const char *, const char *);
Jakub Jelen def1de
 int	 kex_assemble_names(char **, const char *, const char *);
Jakub Jelen def1de
+int	 kex_gss_names_valid(const char *);
Jakub Jelen def1de
 
Jakub Jelen def1de
 int	 kex_exchange_identification(struct ssh *, int, const char *);
Jakub Jelen def1de
 
Jakub Jelen 51f5c1
@@ -202,6 +219,12 @@ int	 kexgex_client(struct ssh *);
Jakub Jelen def1de
 int	 kexgex_server(struct ssh *);
Jakub Jelen def1de
 int	 kex_gen_client(struct ssh *);
Jakub Jelen def1de
 int	 kex_gen_server(struct ssh *);
Jakub Jelen 51f5c1
+#if defined(GSSAPI) && defined(WITH_OPENSSL)
Jakub Jelen def1de
+int	 kexgssgex_client(struct ssh *);
Jakub Jelen def1de
+int	 kexgssgex_server(struct ssh *);
Jakub Jelen def1de
+int	 kexgss_client(struct ssh *);
Jakub Jelen def1de
+int	 kexgss_server(struct ssh *);
Jakub Jelen def1de
+#endif
Jakub Jelen def1de
 
Jakub Jelen def1de
 int	 kex_dh_keypair(struct kex *);
Jakub Jelen def1de
 int	 kex_dh_enc(struct kex *, const struct sshbuf *, struct sshbuf **,
Jakub Jelen 51f5c1
@@ -234,6 +257,12 @@ int	 kexgex_hash(int, const struct sshbuf *, const struct sshbuf *,
Jakub Jelen def1de
     const BIGNUM *, const u_char *, size_t,
Jakub Jelen def1de
     u_char *, size_t *);
Jakub Jelen def1de
 
Jakub Jelen def1de
+int	 kex_gen_hash(int hash_alg, const struct sshbuf *client_version,
Jakub Jelen def1de
+    const struct sshbuf *server_version, const struct sshbuf *client_kexinit,
Jakub Jelen def1de
+    const struct sshbuf *server_kexinit, const struct sshbuf *server_host_key_blob,
Jakub Jelen def1de
+    const struct sshbuf *client_pub, const struct sshbuf *server_pub,
Jakub Jelen def1de
+    const struct sshbuf *shared_secret, u_char *hash, size_t *hashlen);
Jakub Jelen def1de
+
Jakub Jelen def1de
 void	kexc25519_keygen(u_char key[CURVE25519_SIZE], u_char pub[CURVE25519_SIZE])
Jakub Jelen def1de
 	__attribute__((__bounded__(__minbytes__, 1, CURVE25519_SIZE)))
Jakub Jelen def1de
 	__attribute__((__bounded__(__minbytes__, 2, CURVE25519_SIZE)));
Jakub Jelen def1de
diff --git a/kexdh.c b/kexdh.c
Jakub Jelen def1de
index 67133e33..edaa4676 100644
Jakub Jelen def1de
--- a/kexdh.c
Jakub Jelen def1de
+++ b/kexdh.c
Jakub Jelen def1de
@@ -48,13 +48,23 @@ kex_dh_keygen(struct kex *kex)
Jakub Jelen def1de
 {
Jakub Jelen def1de
 	switch (kex->kex_type) {
Jakub Jelen def1de
 	case KEX_DH_GRP1_SHA1:
Jakub Jelen def1de
+#ifdef GSSAPI
Jakub Jelen def1de
+	case KEX_GSS_GRP1_SHA1:
Jakub Jelen def1de
+#endif
Jakub Jelen def1de
 		kex->dh = dh_new_group1();
Jakub Jelen def1de
 		break;
Jakub Jelen def1de
 	case KEX_DH_GRP14_SHA1:
Jakub Jelen def1de
 	case KEX_DH_GRP14_SHA256:
Jakub Jelen def1de
+#ifdef GSSAPI
Jakub Jelen def1de
+	case KEX_GSS_GRP14_SHA1:
Jakub Jelen def1de
+	case KEX_GSS_GRP14_SHA256:
Jakub Jelen def1de
+#endif
Jakub Jelen def1de
 		kex->dh = dh_new_group14();
Jakub Jelen def1de
 		break;
Jakub Jelen def1de
 	case KEX_DH_GRP16_SHA512:
Jakub Jelen def1de
+#ifdef GSSAPI
Jakub Jelen def1de
+	case KEX_GSS_GRP16_SHA512:
Jakub Jelen def1de
+#endif
Jakub Jelen def1de
 		kex->dh = dh_new_group16();
Jakub Jelen def1de
 		break;
Jakub Jelen def1de
 	case KEX_DH_GRP18_SHA512:
Jakub Jelen def1de
diff --git a/kexgen.c b/kexgen.c
Jakub Jelen 51f5c1
index 69348b96..c0e8c2f4 100644
Jakub Jelen def1de
--- a/kexgen.c
Jakub Jelen def1de
+++ b/kexgen.c
Jakub Jelen 51f5c1
@@ -44,7 +44,7 @@
Jakub Jelen def1de
 static int input_kex_gen_init(int, u_int32_t, struct ssh *);
Jakub Jelen def1de
 static int input_kex_gen_reply(int type, u_int32_t seq, struct ssh *ssh);
Jakub Jelen def1de
 
Jakub Jelen def1de
-static int
Jakub Jelen def1de
+int
Jakub Jelen def1de
 kex_gen_hash(
Jakub Jelen def1de
     int hash_alg,
Jakub Jelen def1de
     const struct sshbuf *client_version,
Jakub Jelen def1de
diff --git a/kexgssc.c b/kexgssc.c
Jakub Jelen def1de
new file mode 100644
Jakub Jelen 51f5c1
index 00000000..f6e1405e
Jakub Jelen def1de
--- /dev/null
Jakub Jelen def1de
+++ b/kexgssc.c
Jakub Jelen 51f5c1
@@ -0,0 +1,606 @@
Jakub Jelen def1de
+/*
Jakub Jelen def1de
+ * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved.
Jakub Jelen def1de
+ *
Jakub Jelen def1de
+ * Redistribution and use in source and binary forms, with or without
Jakub Jelen def1de
+ * modification, are permitted provided that the following conditions
Jakub Jelen def1de
+ * are met:
Jakub Jelen def1de
+ * 1. Redistributions of source code must retain the above copyright
Jakub Jelen def1de
+ *    notice, this list of conditions and the following disclaimer.
Jakub Jelen def1de
+ * 2. Redistributions in binary form must reproduce the above copyright
Jakub Jelen def1de
+ *    notice, this list of conditions and the following disclaimer in the
Jakub Jelen def1de
+ *    documentation and/or other materials provided with the distribution.
Jakub Jelen def1de
+ *
Jakub Jelen def1de
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
Jakub Jelen def1de
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
Jakub Jelen def1de
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
Jakub Jelen def1de
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
Jakub Jelen def1de
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
Jakub Jelen def1de
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
Jakub Jelen def1de
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
Jakub Jelen def1de
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
Jakub Jelen def1de
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
Jakub Jelen def1de
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Jakub Jelen def1de
+ */
Jakub Jelen def1de
+
Jakub Jelen def1de
+#include "includes.h"
Jakub Jelen def1de
+
Jakub Jelen def1de
+#if defined(GSSAPI) && defined(WITH_OPENSSL)
Jakub Jelen def1de
+
Jakub Jelen def1de
+#include "includes.h"
Jakub Jelen def1de
+
Jakub Jelen def1de
+#include <openssl/crypto.h>
Jakub Jelen def1de
+#include <openssl/bn.h>
Jakub Jelen def1de
+
Jakub Jelen def1de
+#include <string.h>
Jakub Jelen def1de
+
Jakub Jelen def1de
+#include "xmalloc.h"
Jakub Jelen def1de
+#include "sshbuf.h"
Jakub Jelen def1de
+#include "ssh2.h"
Jakub Jelen def1de
+#include "sshkey.h"
Jakub Jelen def1de
+#include "cipher.h"
Jakub Jelen def1de
+#include "kex.h"
Jakub Jelen def1de
+#include "log.h"
Jakub Jelen def1de
+#include "packet.h"
Jakub Jelen def1de
+#include "dh.h"
Jakub Jelen def1de
+#include "digest.h"
Jakub Jelen def1de
+#include "ssherr.h"
Jakub Jelen def1de
+
Jakub Jelen def1de
+#include "ssh-gss.h"
Jakub Jelen def1de
+
Jakub Jelen def1de
+int
Jakub Jelen def1de
+kexgss_client(struct ssh *ssh)
Jakub Jelen def1de
+{
Jakub Jelen def1de
+	struct kex *kex = ssh->kex;
Jakub Jelen def1de
+	gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER,
Jakub Jelen def1de
+	    recv_tok = GSS_C_EMPTY_BUFFER,
Jakub Jelen def1de
+	    gssbuf, msg_tok = GSS_C_EMPTY_BUFFER, *token_ptr;
Jakub Jelen def1de
+	Gssctxt *ctxt;
Jakub Jelen def1de
+	OM_uint32 maj_status, min_status, ret_flags;
Jakub Jelen def1de
+	struct sshbuf *server_blob = NULL;
Jakub Jelen def1de
+	struct sshbuf *shared_secret = NULL;
Jakub Jelen def1de
+	struct sshbuf *server_host_key_blob = NULL;
Jakub Jelen 51f5c1
+	struct sshbuf *empty = NULL;
Jakub Jelen def1de
+	u_char *msg;
Jakub Jelen def1de
+	int type = 0;
Jakub Jelen def1de
+	int first = 1;
Jakub Jelen def1de
+	u_char hash[SSH_DIGEST_MAX_LENGTH];
Jakub Jelen def1de
+	size_t hashlen;
Jakub Jelen def1de
+	u_char c;
Jakub Jelen def1de
+	int r;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	/* Initialise our GSSAPI world */
Jakub Jelen def1de
+	ssh_gssapi_build_ctx(&ctxt);
Jakub Jelen def1de
+	if (ssh_gssapi_id_kex(ctxt, kex->name, kex->kex_type)
Jakub Jelen def1de
+	    == GSS_C_NO_OID)
Jakub Jelen def1de
+		fatal("Couldn't identify host exchange");
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if (ssh_gssapi_import_name(ctxt, kex->gss_host))
Jakub Jelen def1de
+		fatal("Couldn't import hostname");
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if (kex->gss_client &&
Jakub Jelen def1de
+	    ssh_gssapi_client_identity(ctxt, kex->gss_client))
Jakub Jelen def1de
+		fatal("Couldn't acquire client credentials");
Jakub Jelen def1de
+
Jakub Jelen def1de
+	/* Step 1 */
Jakub Jelen def1de
+	switch (kex->kex_type) {
Jakub Jelen def1de
+	case KEX_GSS_GRP1_SHA1:
Jakub Jelen def1de
+	case KEX_GSS_GRP14_SHA1:
Jakub Jelen def1de
+	case KEX_GSS_GRP14_SHA256:
Jakub Jelen def1de
+	case KEX_GSS_GRP16_SHA512:
Jakub Jelen def1de
+		r = kex_dh_keypair(kex);
Jakub Jelen def1de
+		break;
Jakub Jelen def1de
+	case KEX_GSS_NISTP256_SHA256:
Jakub Jelen def1de
+		r = kex_ecdh_keypair(kex);
Jakub Jelen def1de
+		break;
Jakub Jelen def1de
+	case KEX_GSS_C25519_SHA256:
Jakub Jelen def1de
+		r = kex_c25519_keypair(kex);
Jakub Jelen def1de
+		break;
Jakub Jelen def1de
+	default:
Jakub Jelen def1de
+		fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type);
Jakub Jelen def1de
+	}
Jakub Jelen def1de
+	if (r != 0)
Jakub Jelen def1de
+		return r;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	token_ptr = GSS_C_NO_BUFFER;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	do {
Jakub Jelen def1de
+		debug("Calling gss_init_sec_context");
Jakub Jelen def1de
+
Jakub Jelen def1de
+		maj_status = ssh_gssapi_init_ctx(ctxt,
Jakub Jelen def1de
+		    kex->gss_deleg_creds, token_ptr, &send_tok,
Jakub Jelen def1de
+		    &ret_flags);
Jakub Jelen def1de
+
Jakub Jelen def1de
+		if (GSS_ERROR(maj_status)) {
Jakub Jelen def1de
+			/* XXX Useles code: Missing send? */
Jakub Jelen def1de
+			if (send_tok.length != 0) {
Jakub Jelen def1de
+				if ((r = sshpkt_start(ssh,
Jakub Jelen def1de
+				        SSH2_MSG_KEXGSS_CONTINUE)) != 0 ||
Jakub Jelen def1de
+				    (r = sshpkt_put_string(ssh, send_tok.value,
Jakub Jelen def1de
+				        send_tok.length)) != 0)
Jakub Jelen def1de
+					fatal("sshpkt failed: %s", ssh_err(r));
Jakub Jelen def1de
+			}
Jakub Jelen def1de
+			fatal("gss_init_context failed");
Jakub Jelen def1de
+		}
Jakub Jelen def1de
+
Jakub Jelen def1de
+		/* If we've got an old receive buffer get rid of it */
Jakub Jelen def1de
+		if (token_ptr != GSS_C_NO_BUFFER)
Jakub Jelen def1de
+			gss_release_buffer(&min_status, &recv_tok);
Jakub Jelen def1de
+
Jakub Jelen def1de
+		if (maj_status == GSS_S_COMPLETE) {
Jakub Jelen def1de
+			/* If mutual state flag is not true, kex fails */
Jakub Jelen def1de
+			if (!(ret_flags & GSS_C_MUTUAL_FLAG))
Jakub Jelen def1de
+				fatal("Mutual authentication failed");
Jakub Jelen def1de
+
Jakub Jelen def1de
+			/* If integ avail flag is not true kex fails */
Jakub Jelen def1de
+			if (!(ret_flags & GSS_C_INTEG_FLAG))
Jakub Jelen def1de
+				fatal("Integrity check failed");
Jakub Jelen def1de
+		}
Jakub Jelen def1de
+
Jakub Jelen def1de
+		/*
Jakub Jelen def1de
+		 * If we have data to send, then the last message that we
Jakub Jelen def1de
+		 * received cannot have been a 'complete'.
Jakub Jelen def1de
+		 */
Jakub Jelen def1de
+		if (send_tok.length != 0) {
Jakub Jelen def1de
+			if (first) {
Jakub Jelen def1de
+				if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_INIT)) != 0 ||
Jakub Jelen def1de
+				    (r = sshpkt_put_string(ssh, send_tok.value,
Jakub Jelen def1de
+				        send_tok.length)) != 0 ||
Jakub Jelen def1de
+				    (r = sshpkt_put_stringb(ssh, kex->client_pub)) != 0)
Jakub Jelen def1de
+					fatal("failed to construct packet: %s", ssh_err(r));
Jakub Jelen def1de
+				first = 0;
Jakub Jelen def1de
+			} else {
Jakub Jelen def1de
+				if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_CONTINUE)) != 0 ||
Jakub Jelen def1de
+				    (r = sshpkt_put_string(ssh, send_tok.value,
Jakub Jelen def1de
+				        send_tok.length)) != 0)
Jakub Jelen def1de
+					fatal("failed to construct packet: %s", ssh_err(r));
Jakub Jelen def1de
+			}
Jakub Jelen def1de
+			if ((r = sshpkt_send(ssh)) != 0)
Jakub Jelen def1de
+				fatal("failed to send packet: %s", ssh_err(r));
Jakub Jelen def1de
+			gss_release_buffer(&min_status, &send_tok);
Jakub Jelen def1de
+
Jakub Jelen def1de
+			/* If we've sent them data, they should reply */
Jakub Jelen def1de
+			do {
Jakub Jelen def1de
+				type = ssh_packet_read(ssh);
Jakub Jelen def1de
+				if (type == SSH2_MSG_KEXGSS_HOSTKEY) {
Jakub Jelen def1de
+					debug("Received KEXGSS_HOSTKEY");
Jakub Jelen def1de
+					if (server_host_key_blob)
Jakub Jelen def1de
+						fatal("Server host key received more than once");
Jakub Jelen def1de
+					if ((r = sshpkt_getb_froms(ssh, &server_host_key_blob)) != 0)
Jakub Jelen def1de
+						fatal("Failed to read server host key: %s", ssh_err(r));
Jakub Jelen def1de
+				}
Jakub Jelen def1de
+			} while (type == SSH2_MSG_KEXGSS_HOSTKEY);
Jakub Jelen def1de
+
Jakub Jelen def1de
+			switch (type) {
Jakub Jelen def1de
+			case SSH2_MSG_KEXGSS_CONTINUE:
Jakub Jelen def1de
+				debug("Received GSSAPI_CONTINUE");
Jakub Jelen def1de
+				if (maj_status == GSS_S_COMPLETE)
Jakub Jelen def1de
+					fatal("GSSAPI Continue received from server when complete");
Jakub Jelen def1de
+				if ((r = ssh_gssapi_sshpkt_get_buffer_desc(ssh,
Jakub Jelen def1de
+				        &recv_tok)) != 0 ||
Jakub Jelen def1de
+				    (r = sshpkt_get_end(ssh)) != 0)
Jakub Jelen def1de
+					fatal("Failed to read token: %s", ssh_err(r));
Jakub Jelen def1de
+				break;
Jakub Jelen def1de
+			case SSH2_MSG_KEXGSS_COMPLETE:
Jakub Jelen def1de
+				debug("Received GSSAPI_COMPLETE");
Jakub Jelen def1de
+				if (msg_tok.value != NULL)
Jakub Jelen def1de
+				        fatal("Received GSSAPI_COMPLETE twice?");
Jakub Jelen def1de
+				if ((r = sshpkt_getb_froms(ssh, &server_blob)) != 0 ||
Jakub Jelen def1de
+				    (r = ssh_gssapi_sshpkt_get_buffer_desc(ssh,
Jakub Jelen def1de
+				        &msg_tok)) != 0)
Jakub Jelen def1de
+					fatal("Failed to read message: %s", ssh_err(r));
Jakub Jelen def1de
+
Jakub Jelen def1de
+				/* Is there a token included? */
Jakub Jelen def1de
+				if ((r = sshpkt_get_u8(ssh, &c)) != 0)
Jakub Jelen def1de
+					fatal("sshpkt failed: %s", ssh_err(r));
Jakub Jelen def1de
+				if (c) {
Jakub Jelen def1de
+					if ((r = ssh_gssapi_sshpkt_get_buffer_desc(
Jakub Jelen def1de
+					    ssh, &recv_tok)) != 0)
Jakub Jelen def1de
+						fatal("Failed to read token: %s", ssh_err(r));
Jakub Jelen def1de
+					/* If we're already complete - protocol error */
Jakub Jelen def1de
+					if (maj_status == GSS_S_COMPLETE)
Jakub Jelen def1de
+						sshpkt_disconnect(ssh, "Protocol error: received token when complete");
Jakub Jelen def1de
+				} else {
Jakub Jelen def1de
+					/* No token included */
Jakub Jelen def1de
+					if (maj_status != GSS_S_COMPLETE)
Jakub Jelen def1de
+						sshpkt_disconnect(ssh, "Protocol error: did not receive final token");
Jakub Jelen def1de
+				}
Jakub Jelen def1de
+				if ((r = sshpkt_get_end(ssh)) != 0) {
Jakub Jelen def1de
+					fatal("Expecting end of packet.");
Jakub Jelen def1de
+				}
Jakub Jelen def1de
+				break;
Jakub Jelen def1de
+			case SSH2_MSG_KEXGSS_ERROR:
Jakub Jelen def1de
+				debug("Received Error");
Jakub Jelen def1de
+				if ((r = sshpkt_get_u32(ssh, &maj_status)) != 0 ||
Jakub Jelen def1de
+				    (r = sshpkt_get_u32(ssh, &min_status)) != 0 ||
Jakub Jelen def1de
+				    (r = sshpkt_get_string(ssh, &msg, NULL)) != 0 ||
Jakub Jelen def1de
+				    (r = sshpkt_get_string(ssh, NULL, NULL)) != 0 || /* lang tag */
Jakub Jelen def1de
+				    (r = sshpkt_get_end(ssh)) != 0)
Jakub Jelen def1de
+					fatal("sshpkt_get failed: %s", ssh_err(r));
Jakub Jelen def1de
+				fatal("GSSAPI Error: \n%.400s", msg);
Jakub Jelen def1de
+			default:
Jakub Jelen def1de
+				sshpkt_disconnect(ssh, "Protocol error: didn't expect packet type %d",
Jakub Jelen def1de
+				    type);
Jakub Jelen def1de
+			}
Jakub Jelen def1de
+			token_ptr = &recv_tok;
Jakub Jelen def1de
+		} else {
Jakub Jelen def1de
+			/* No data, and not complete */
Jakub Jelen def1de
+			if (maj_status != GSS_S_COMPLETE)
Jakub Jelen def1de
+				fatal("Not complete, and no token output");
Jakub Jelen def1de
+		}
Jakub Jelen def1de
+	} while (maj_status & GSS_S_CONTINUE_NEEDED);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	/*
Jakub Jelen def1de
+	 * We _must_ have received a COMPLETE message in reply from the
Jakub Jelen def1de
+	 * server, which will have set server_blob and msg_tok
Jakub Jelen def1de
+	 */
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if (type != SSH2_MSG_KEXGSS_COMPLETE)
Jakub Jelen def1de
+		fatal("Didn't receive a SSH2_MSG_KEXGSS_COMPLETE when I expected it");
Jakub Jelen def1de
+
Jakub Jelen def1de
+	/* compute shared secret */
Jakub Jelen def1de
+	switch (kex->kex_type) {
Jakub Jelen def1de
+	case KEX_GSS_GRP1_SHA1:
Jakub Jelen def1de
+	case KEX_GSS_GRP14_SHA1:
Jakub Jelen def1de
+	case KEX_GSS_GRP14_SHA256:
Jakub Jelen def1de
+	case KEX_GSS_GRP16_SHA512:
Jakub Jelen def1de
+		r = kex_dh_dec(kex, server_blob, &shared_secret);
Jakub Jelen def1de
+		break;
Jakub Jelen def1de
+	case KEX_GSS_C25519_SHA256:
Jakub Jelen def1de
+		if (sshbuf_ptr(server_blob)[sshbuf_len(server_blob)] & 0x80)
Jakub Jelen def1de
+			fatal("The received key has MSB of last octet set!");
Jakub Jelen def1de
+		r = kex_c25519_dec(kex, server_blob, &shared_secret);
Jakub Jelen def1de
+		break;
Jakub Jelen def1de
+	case KEX_GSS_NISTP256_SHA256:
Jakub Jelen def1de
+		if (sshbuf_len(server_blob) != 65)
Jakub Jelen def1de
+			fatal("The received NIST-P256 key did not match"
Jakub Jelen def1de
+			    "expected length (expected 65, got %zu)", sshbuf_len(server_blob));
Jakub Jelen def1de
+
Jakub Jelen def1de
+		if (sshbuf_ptr(server_blob)[0] != POINT_CONVERSION_UNCOMPRESSED)
Jakub Jelen def1de
+			fatal("The received NIST-P256 key does not have first octet 0x04");
Jakub Jelen def1de
+
Jakub Jelen def1de
+		r = kex_ecdh_dec(kex, server_blob, &shared_secret);
Jakub Jelen def1de
+		break;
Jakub Jelen def1de
+	default:
Jakub Jelen def1de
+		r = SSH_ERR_INVALID_ARGUMENT;
Jakub Jelen def1de
+		break;
Jakub Jelen def1de
+	}
Jakub Jelen def1de
+	if (r != 0)
Jakub Jelen def1de
+		goto out;
Jakub Jelen def1de
+
Jakub Jelen 51f5c1
+	if ((empty = sshbuf_new()) == NULL) {
Jakub Jelen 51f5c1
+		r = SSH_ERR_ALLOC_FAIL;
Jakub Jelen 51f5c1
+		goto out;
Jakub Jelen 51f5c1
+	}
Jakub Jelen 51f5c1
+
Jakub Jelen def1de
+	hashlen = sizeof(hash);
Jakub Jelen def1de
+	if ((r = kex_gen_hash(
Jakub Jelen def1de
+	    kex->hash_alg,
Jakub Jelen def1de
+	    kex->client_version,
Jakub Jelen def1de
+	    kex->server_version,
Jakub Jelen def1de
+	    kex->my,
Jakub Jelen def1de
+	    kex->peer,
Jakub Jelen def1de
+	    (server_host_key_blob ? server_host_key_blob : empty),
Jakub Jelen def1de
+	    kex->client_pub,
Jakub Jelen def1de
+	    server_blob,
Jakub Jelen def1de
+	    shared_secret,
Jakub Jelen def1de
+	    hash, &hashlen)) != 0)
Jakub Jelen def1de
+		fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	gssbuf.value = hash;
Jakub Jelen def1de
+	gssbuf.length = hashlen;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	/* Verify that the hash matches the MIC we just got. */
Jakub Jelen def1de
+	if (GSS_ERROR(ssh_gssapi_checkmic(ctxt, &gssbuf, &msg_tok)))
Jakub Jelen def1de
+		sshpkt_disconnect(ssh, "Hash's MIC didn't verify");
Jakub Jelen def1de
+
Jakub Jelen def1de
+	gss_release_buffer(&min_status, &msg_tok);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if (kex->gss_deleg_creds)
Jakub Jelen def1de
+		ssh_gssapi_credentials_updated(ctxt);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if (gss_kex_context == NULL)
Jakub Jelen def1de
+		gss_kex_context = ctxt;
Jakub Jelen def1de
+	else
Jakub Jelen def1de
+		ssh_gssapi_delete_ctx(&ctxt);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if ((r = kex_derive_keys(ssh, hash, hashlen, shared_secret)) == 0)
Jakub Jelen def1de
+		r = kex_send_newkeys(ssh);
Jakub Jelen def1de
+
Jakub Jelen def1de
+out:
Jakub Jelen def1de
+	explicit_bzero(hash, sizeof(hash));
Jakub Jelen def1de
+	explicit_bzero(kex->c25519_client_key, sizeof(kex->c25519_client_key));
Jakub Jelen def1de
+	sshbuf_free(empty);
Jakub Jelen def1de
+	sshbuf_free(server_host_key_blob);
Jakub Jelen def1de
+	sshbuf_free(server_blob);
Jakub Jelen def1de
+	sshbuf_free(shared_secret);
Jakub Jelen def1de
+	sshbuf_free(kex->client_pub);
Jakub Jelen def1de
+	kex->client_pub = NULL;
Jakub Jelen def1de
+	return r;
Jakub Jelen def1de
+}
Jakub Jelen def1de
+
Jakub Jelen def1de
+int
Jakub Jelen def1de
+kexgssgex_client(struct ssh *ssh)
Jakub Jelen def1de
+{
Jakub Jelen def1de
+	struct kex *kex = ssh->kex;
Jakub Jelen def1de
+	gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER,
Jakub Jelen def1de
+	    recv_tok = GSS_C_EMPTY_BUFFER, gssbuf,
Jakub Jelen def1de
+            msg_tok = GSS_C_EMPTY_BUFFER, *token_ptr;
Jakub Jelen def1de
+	Gssctxt *ctxt;
Jakub Jelen def1de
+	OM_uint32 maj_status, min_status, ret_flags;
Jakub Jelen def1de
+	struct sshbuf *shared_secret = NULL;
Jakub Jelen def1de
+	BIGNUM *p = NULL;
Jakub Jelen def1de
+	BIGNUM *g = NULL;
Jakub Jelen def1de
+	struct sshbuf *buf = NULL;
Jakub Jelen def1de
+	struct sshbuf *server_host_key_blob = NULL;
Jakub Jelen def1de
+	struct sshbuf *server_blob = NULL;
Jakub Jelen def1de
+	BIGNUM *dh_server_pub = NULL;
Jakub Jelen def1de
+	u_char *msg;
Jakub Jelen def1de
+	int type = 0;
Jakub Jelen def1de
+	int first = 1;
Jakub Jelen def1de
+	u_char hash[SSH_DIGEST_MAX_LENGTH];
Jakub Jelen def1de
+	size_t hashlen;
Jakub Jelen def1de
+	const BIGNUM *pub_key, *dh_p, *dh_g;
Jakub Jelen def1de
+	int nbits = 0, min = DH_GRP_MIN, max = DH_GRP_MAX;
Jakub Jelen 51f5c1
+	struct sshbuf *empty = NULL;
Jakub Jelen def1de
+	u_char c;
Jakub Jelen def1de
+	int r;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	/* Initialise our GSSAPI world */
Jakub Jelen def1de
+	ssh_gssapi_build_ctx(&ctxt);
Jakub Jelen def1de
+	if (ssh_gssapi_id_kex(ctxt, kex->name, kex->kex_type)
Jakub Jelen def1de
+	    == GSS_C_NO_OID)
Jakub Jelen def1de
+		fatal("Couldn't identify host exchange");
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if (ssh_gssapi_import_name(ctxt, kex->gss_host))
Jakub Jelen def1de
+		fatal("Couldn't import hostname");
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if (kex->gss_client &&
Jakub Jelen def1de
+	    ssh_gssapi_client_identity(ctxt, kex->gss_client))
Jakub Jelen def1de
+		fatal("Couldn't acquire client credentials");
Jakub Jelen def1de
+
Jakub Jelen def1de
+	debug("Doing group exchange");
Jakub Jelen def1de
+	nbits = dh_estimate(kex->dh_need * 8);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	kex->min = DH_GRP_MIN;
Jakub Jelen def1de
+	kex->max = DH_GRP_MAX;
Jakub Jelen def1de
+	kex->nbits = nbits;
Jakub Jelen def1de
+	if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_GROUPREQ)) != 0 ||
Jakub Jelen def1de
+	    (r = sshpkt_put_u32(ssh, min)) != 0 ||
Jakub Jelen def1de
+	    (r = sshpkt_put_u32(ssh, nbits)) != 0 ||
Jakub Jelen def1de
+	    (r = sshpkt_put_u32(ssh, max)) != 0 ||
Jakub Jelen def1de
+	    (r = sshpkt_send(ssh)) != 0)
Jakub Jelen def1de
+		fatal("Failed to construct a packet: %s", ssh_err(r));
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if ((r = ssh_packet_read_expect(ssh, SSH2_MSG_KEXGSS_GROUP)) != 0)
Jakub Jelen def1de
+		fatal("Error: %s", ssh_err(r));
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if ((r = sshpkt_get_bignum2(ssh, &p)) != 0 ||
Jakub Jelen def1de
+	    (r = sshpkt_get_bignum2(ssh, &g)) != 0 ||
Jakub Jelen def1de
+	    (r = sshpkt_get_end(ssh)) != 0)
Jakub Jelen def1de
+		fatal("shpkt_get_bignum2 failed: %s", ssh_err(r));
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if (BN_num_bits(p) < min || BN_num_bits(p) > max)
Jakub Jelen def1de
+		fatal("GSSGRP_GEX group out of range: %d !< %d !< %d",
Jakub Jelen def1de
+		    min, BN_num_bits(p), max);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if ((kex->dh = dh_new_group(g, p)) == NULL)
Jakub Jelen def1de
+		fatal("dn_new_group() failed");
Jakub Jelen def1de
+	p = g = NULL; /* belong to kex->dh now */
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if ((r = dh_gen_key(kex->dh, kex->we_need * 8)) != 0)
Jakub Jelen def1de
+		goto out;
Jakub Jelen def1de
+	DH_get0_key(kex->dh, &pub_key, NULL);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	token_ptr = GSS_C_NO_BUFFER;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	do {
Jakub Jelen def1de
+		/* Step 2 - call GSS_Init_sec_context() */
Jakub Jelen def1de
+		debug("Calling gss_init_sec_context");
Jakub Jelen def1de
+
Jakub Jelen def1de
+		maj_status = ssh_gssapi_init_ctx(ctxt,
Jakub Jelen def1de
+		    kex->gss_deleg_creds, token_ptr, &send_tok,
Jakub Jelen def1de
+		    &ret_flags);
Jakub Jelen def1de
+
Jakub Jelen def1de
+		if (GSS_ERROR(maj_status)) {
Jakub Jelen def1de
+			/* XXX Useles code: Missing send? */
Jakub Jelen def1de
+			if (send_tok.length != 0) {
Jakub Jelen def1de
+				if ((r = sshpkt_start(ssh,
Jakub Jelen def1de
+				        SSH2_MSG_KEXGSS_CONTINUE)) != 0 ||
Jakub Jelen def1de
+				    (r = sshpkt_put_string(ssh, send_tok.value,
Jakub Jelen def1de
+				        send_tok.length)) != 0)
Jakub Jelen def1de
+					fatal("sshpkt failed: %s", ssh_err(r));
Jakub Jelen def1de
+			}
Jakub Jelen def1de
+			fatal("gss_init_context failed");
Jakub Jelen def1de
+		}
Jakub Jelen def1de
+
Jakub Jelen def1de
+		/* If we've got an old receive buffer get rid of it */
Jakub Jelen def1de
+		if (token_ptr != GSS_C_NO_BUFFER)
Jakub Jelen def1de
+			gss_release_buffer(&min_status, &recv_tok);
Jakub Jelen def1de
+
Jakub Jelen def1de
+		if (maj_status == GSS_S_COMPLETE) {
Jakub Jelen def1de
+			/* If mutual state flag is not true, kex fails */
Jakub Jelen def1de
+			if (!(ret_flags & GSS_C_MUTUAL_FLAG))
Jakub Jelen def1de
+				fatal("Mutual authentication failed");
Jakub Jelen def1de
+
Jakub Jelen def1de
+			/* If integ avail flag is not true kex fails */
Jakub Jelen def1de
+			if (!(ret_flags & GSS_C_INTEG_FLAG))
Jakub Jelen def1de
+				fatal("Integrity check failed");
Jakub Jelen def1de
+		}
Jakub Jelen def1de
+
Jakub Jelen def1de
+		/*
Jakub Jelen def1de
+		 * If we have data to send, then the last message that we
Jakub Jelen def1de
+		 * received cannot have been a 'complete'.
Jakub Jelen def1de
+		 */
Jakub Jelen def1de
+		if (send_tok.length != 0) {
Jakub Jelen def1de
+			if (first) {
Jakub Jelen def1de
+				if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_INIT)) != 0 ||
Jakub Jelen def1de
+				    (r = sshpkt_put_string(ssh, send_tok.value,
Jakub Jelen def1de
+				        send_tok.length)) != 0 ||
Jakub Jelen def1de
+				    (r = sshpkt_put_bignum2(ssh, pub_key)) != 0)
Jakub Jelen def1de
+					fatal("sshpkt failed: %s", ssh_err(r));
Jakub Jelen def1de
+				first = 0;
Jakub Jelen def1de
+			} else {
Jakub Jelen def1de
+				if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_CONTINUE)) != 0 ||
Jakub Jelen def1de
+				    (r = sshpkt_put_string(ssh,send_tok.value,
Jakub Jelen def1de
+				        send_tok.length)) != 0)
Jakub Jelen def1de
+					fatal("sshpkt failed: %s", ssh_err(r));
Jakub Jelen def1de
+			}
Jakub Jelen def1de
+			if ((r = sshpkt_send(ssh)) != 0)
Jakub Jelen def1de
+				fatal("sshpkt_send failed: %s", ssh_err(r));
Jakub Jelen def1de
+			gss_release_buffer(&min_status, &send_tok);
Jakub Jelen def1de
+
Jakub Jelen def1de
+			/* If we've sent them data, they should reply */
Jakub Jelen def1de
+			do {
Jakub Jelen def1de
+				type = ssh_packet_read(ssh);
Jakub Jelen def1de
+				if (type == SSH2_MSG_KEXGSS_HOSTKEY) {
Jakub Jelen def1de
+					debug("Received KEXGSS_HOSTKEY");
Jakub Jelen def1de
+					if (server_host_key_blob)
Jakub Jelen def1de
+						fatal("Server host key received more than once");
Jakub Jelen def1de
+					if ((r = sshpkt_getb_froms(ssh, &server_host_key_blob)) != 0)
Jakub Jelen def1de
+						fatal("sshpkt failed: %s", ssh_err(r));
Jakub Jelen def1de
+				}
Jakub Jelen def1de
+			} while (type == SSH2_MSG_KEXGSS_HOSTKEY);
Jakub Jelen def1de
+
Jakub Jelen def1de
+			switch (type) {
Jakub Jelen def1de
+			case SSH2_MSG_KEXGSS_CONTINUE:
Jakub Jelen def1de
+				debug("Received GSSAPI_CONTINUE");
Jakub Jelen def1de
+				if (maj_status == GSS_S_COMPLETE)
Jakub Jelen def1de
+					fatal("GSSAPI Continue received from server when complete");
Jakub Jelen def1de
+				if ((r = ssh_gssapi_sshpkt_get_buffer_desc(ssh,
Jakub Jelen def1de
+				        &recv_tok)) != 0 ||
Jakub Jelen def1de
+				    (r = sshpkt_get_end(ssh)) != 0)
Jakub Jelen def1de
+					fatal("sshpkt failed: %s", ssh_err(r));
Jakub Jelen def1de
+				break;
Jakub Jelen def1de
+			case SSH2_MSG_KEXGSS_COMPLETE:
Jakub Jelen def1de
+				debug("Received GSSAPI_COMPLETE");
Jakub Jelen def1de
+				if (msg_tok.value != NULL)
Jakub Jelen def1de
+				        fatal("Received GSSAPI_COMPLETE twice?");
Jakub Jelen def1de
+				if ((r = sshpkt_getb_froms(ssh, &server_blob)) != 0 ||
Jakub Jelen def1de
+				    (r = ssh_gssapi_sshpkt_get_buffer_desc(ssh,
Jakub Jelen def1de
+				        &msg_tok)) != 0)
Jakub Jelen def1de
+					fatal("sshpkt failed: %s", ssh_err(r));
Jakub Jelen def1de
+
Jakub Jelen def1de
+				/* Is there a token included? */
Jakub Jelen def1de
+				if ((r = sshpkt_get_u8(ssh, &c)) != 0)
Jakub Jelen def1de
+					fatal("sshpkt failed: %s", ssh_err(r));
Jakub Jelen def1de
+				if (c) {
Jakub Jelen def1de
+					if ((r = ssh_gssapi_sshpkt_get_buffer_desc(
Jakub Jelen def1de
+					        ssh, &recv_tok)) != 0 ||
Jakub Jelen def1de
+					    (r = sshpkt_get_end(ssh)) != 0)
Jakub Jelen def1de
+						fatal("sshpkt failed: %s", ssh_err(r));
Jakub Jelen def1de
+					/* If we're already complete - protocol error */
Jakub Jelen def1de
+					if (maj_status == GSS_S_COMPLETE)
Jakub Jelen def1de
+						sshpkt_disconnect(ssh, "Protocol error: received token when complete");
Jakub Jelen def1de
+				} else {
Jakub Jelen def1de
+					/* No token included */
Jakub Jelen def1de
+					if (maj_status != GSS_S_COMPLETE)
Jakub Jelen def1de
+						sshpkt_disconnect(ssh, "Protocol error: did not receive final token");
Jakub Jelen def1de
+				}
Jakub Jelen def1de
+				break;
Jakub Jelen def1de
+			case SSH2_MSG_KEXGSS_ERROR:
Jakub Jelen def1de
+				debug("Received Error");
Jakub Jelen def1de
+				if ((r = sshpkt_get_u32(ssh, &maj_status)) != 0 ||
Jakub Jelen def1de
+				    (r = sshpkt_get_u32(ssh, &min_status)) != 0 ||
Jakub Jelen def1de
+				    (r = sshpkt_get_string(ssh, &msg, NULL)) != 0 ||
Jakub Jelen def1de
+				    (r = sshpkt_get_string(ssh, NULL, NULL)) != 0 || /* lang tag */
Jakub Jelen def1de
+				    (r = sshpkt_get_end(ssh)) != 0)
Jakub Jelen def1de
+					fatal("sshpkt failed: %s", ssh_err(r));
Jakub Jelen def1de
+				fatal("GSSAPI Error: \n%.400s", msg);
Jakub Jelen def1de
+			default:
Jakub Jelen def1de
+				sshpkt_disconnect(ssh, "Protocol error: didn't expect packet type %d",
Jakub Jelen def1de
+				    type);
Jakub Jelen def1de
+			}
Jakub Jelen def1de
+			token_ptr = &recv_tok;
Jakub Jelen def1de
+		} else {
Jakub Jelen def1de
+			/* No data, and not complete */
Jakub Jelen def1de
+			if (maj_status != GSS_S_COMPLETE)
Jakub Jelen def1de
+				fatal("Not complete, and no token output");
Jakub Jelen def1de
+		}
Jakub Jelen def1de
+	} while (maj_status & GSS_S_CONTINUE_NEEDED);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	/*
Jakub Jelen def1de
+	 * We _must_ have received a COMPLETE message in reply from the
Jakub Jelen def1de
+	 * server, which will have set dh_server_pub and msg_tok
Jakub Jelen def1de
+	 */
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if (type != SSH2_MSG_KEXGSS_COMPLETE)
Jakub Jelen def1de
+		fatal("Didn't receive a SSH2_MSG_KEXGSS_COMPLETE when I expected it");
Jakub Jelen def1de
+
Jakub Jelen def1de
+	/* 7. C verifies that the key Q_S is valid */
Jakub Jelen def1de
+	/* 8. C computes shared secret */
Jakub Jelen def1de
+	if ((buf = sshbuf_new()) == NULL ||
Jakub Jelen def1de
+	    (r = sshbuf_put_stringb(buf, server_blob)) != 0 ||
Jakub Jelen def1de
+	    (r = sshbuf_get_bignum2(buf, &dh_server_pub)) != 0)
Jakub Jelen def1de
+		goto out;
Jakub Jelen def1de
+	sshbuf_free(buf);
Jakub Jelen 51f5c1
+	buf = NULL;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if ((shared_secret = sshbuf_new()) == NULL) {
Jakub Jelen def1de
+		r = SSH_ERR_ALLOC_FAIL;
Jakub Jelen def1de
+		goto out;
Jakub Jelen def1de
+	}
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if ((r = kex_dh_compute_key(kex, dh_server_pub, shared_secret)) != 0)
Jakub Jelen def1de
+		goto out;
Jakub Jelen 51f5c1
+	if ((empty = sshbuf_new()) == NULL) {
Jakub Jelen 51f5c1
+		r = SSH_ERR_ALLOC_FAIL;
Jakub Jelen 51f5c1
+		goto out;
Jakub Jelen 51f5c1
+	}
Jakub Jelen def1de
+
Jakub Jelen def1de
+	DH_get0_pqg(kex->dh, &dh_p, NULL, &dh_g);
Jakub Jelen def1de
+	hashlen = sizeof(hash);
Jakub Jelen def1de
+	if ((r = kexgex_hash(
Jakub Jelen def1de
+	    kex->hash_alg,
Jakub Jelen def1de
+	    kex->client_version,
Jakub Jelen def1de
+	    kex->server_version,
Jakub Jelen def1de
+	    kex->my,
Jakub Jelen def1de
+	    kex->peer,
Jakub Jelen def1de
+	    (server_host_key_blob ? server_host_key_blob : empty),
Jakub Jelen def1de
+ 	    kex->min, kex->nbits, kex->max,
Jakub Jelen def1de
+	    dh_p, dh_g,
Jakub Jelen def1de
+	    pub_key,
Jakub Jelen def1de
+	    dh_server_pub,
Jakub Jelen def1de
+	    sshbuf_ptr(shared_secret), sshbuf_len(shared_secret),
Jakub Jelen def1de
+	    hash, &hashlen)) != 0)
Jakub Jelen def1de
+		fatal("Failed to calculate hash: %s", ssh_err(r));
Jakub Jelen def1de
+
Jakub Jelen def1de
+	gssbuf.value = hash;
Jakub Jelen def1de
+	gssbuf.length = hashlen;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	/* Verify that the hash matches the MIC we just got. */
Jakub Jelen def1de
+	if (GSS_ERROR(ssh_gssapi_checkmic(ctxt, &gssbuf, &msg_tok)))
Jakub Jelen def1de
+		sshpkt_disconnect(ssh, "Hash's MIC didn't verify");
Jakub Jelen def1de
+
Jakub Jelen def1de
+	gss_release_buffer(&min_status, &msg_tok);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	/* save session id */
Jakub Jelen def1de
+	if (kex->session_id == NULL) {
Jakub Jelen def1de
+		kex->session_id_len = hashlen;
Jakub Jelen def1de
+		kex->session_id = xmalloc(kex->session_id_len);
Jakub Jelen def1de
+		memcpy(kex->session_id, hash, kex->session_id_len);
Jakub Jelen def1de
+	}
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if (kex->gss_deleg_creds)
Jakub Jelen def1de
+		ssh_gssapi_credentials_updated(ctxt);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if (gss_kex_context == NULL)
Jakub Jelen def1de
+		gss_kex_context = ctxt;
Jakub Jelen def1de
+	else
Jakub Jelen def1de
+		ssh_gssapi_delete_ctx(&ctxt);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	/* Finally derive the keys and send them */
Jakub Jelen def1de
+	if ((r = kex_derive_keys(ssh, hash, hashlen, shared_secret)) == 0)
Jakub Jelen def1de
+		r = kex_send_newkeys(ssh);
Jakub Jelen def1de
+out:
Jakub Jelen 51f5c1
+	sshbuf_free(buf);
Jakub Jelen def1de
+	sshbuf_free(server_blob);
Jakub Jelen def1de
+	sshbuf_free(empty);
Jakub Jelen def1de
+	explicit_bzero(hash, sizeof(hash));
Jakub Jelen def1de
+	DH_free(kex->dh);
Jakub Jelen def1de
+	kex->dh = NULL;
Jakub Jelen def1de
+	BN_clear_free(dh_server_pub);
Jakub Jelen def1de
+	sshbuf_free(shared_secret);
Jakub Jelen def1de
+	sshbuf_free(server_host_key_blob);
Jakub Jelen def1de
+	return r;
Jakub Jelen def1de
+}
Jakub Jelen def1de
+#endif /* defined(GSSAPI) && defined(WITH_OPENSSL) */
Jakub Jelen def1de
diff --git a/kexgsss.c b/kexgsss.c
Jakub Jelen def1de
new file mode 100644
Jakub Jelen def1de
index 00000000..60bc02de
Jakub Jelen def1de
--- /dev/null
Jakub Jelen def1de
+++ b/kexgsss.c
Jakub Jelen def1de
@@ -0,0 +1,474 @@
Jakub Jelen def1de
+/*
Jakub Jelen def1de
+ * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved.
Jakub Jelen def1de
+ *
Jakub Jelen def1de
+ * Redistribution and use in source and binary forms, with or without
Jakub Jelen def1de
+ * modification, are permitted provided that the following conditions
Jakub Jelen def1de
+ * are met:
Jakub Jelen def1de
+ * 1. Redistributions of source code must retain the above copyright
Jakub Jelen def1de
+ *    notice, this list of conditions and the following disclaimer.
Jakub Jelen def1de
+ * 2. Redistributions in binary form must reproduce the above copyright
Jakub Jelen def1de
+ *    notice, this list of conditions and the following disclaimer in the
Jakub Jelen def1de
+ *    documentation and/or other materials provided with the distribution.
Jakub Jelen def1de
+ *
Jakub Jelen def1de
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
Jakub Jelen def1de
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
Jakub Jelen def1de
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
Jakub Jelen def1de
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
Jakub Jelen def1de
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
Jakub Jelen def1de
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
Jakub Jelen def1de
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
Jakub Jelen def1de
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
Jakub Jelen def1de
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
Jakub Jelen def1de
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Jakub Jelen def1de
+ */
Jakub Jelen def1de
+
Jakub Jelen def1de
+#include "includes.h"
Jakub Jelen def1de
+
Jakub Jelen def1de
+#if defined(GSSAPI) && defined(WITH_OPENSSL)
Jakub Jelen def1de
+
Jakub Jelen def1de
+#include <string.h>
Jakub Jelen def1de
+
Jakub Jelen def1de
+#include <openssl/crypto.h>
Jakub Jelen def1de
+#include <openssl/bn.h>
Jakub Jelen def1de
+
Jakub Jelen def1de
+#include "xmalloc.h"
Jakub Jelen def1de
+#include "sshbuf.h"
Jakub Jelen def1de
+#include "ssh2.h"
Jakub Jelen def1de
+#include "sshkey.h"
Jakub Jelen def1de
+#include "cipher.h"
Jakub Jelen def1de
+#include "kex.h"
Jakub Jelen def1de
+#include "log.h"
Jakub Jelen def1de
+#include "packet.h"
Jakub Jelen def1de
+#include "dh.h"
Jakub Jelen def1de
+#include "ssh-gss.h"
Jakub Jelen def1de
+#include "monitor_wrap.h"
Jakub Jelen def1de
+#include "misc.h"      /* servconf.h needs misc.h for struct ForwardOptions */
Jakub Jelen def1de
+#include "servconf.h"
Jakub Jelen def1de
+#include "ssh-gss.h"
Jakub Jelen def1de
+#include "digest.h"
Jakub Jelen def1de
+#include "ssherr.h"
Jakub Jelen def1de
+
Jakub Jelen def1de
+extern ServerOptions options;
Jakub Jelen def1de
+
Jakub Jelen def1de
+int
Jakub Jelen def1de
+kexgss_server(struct ssh *ssh)
Jakub Jelen def1de
+{
Jakub Jelen def1de
+	struct kex *kex = ssh->kex;
Jakub Jelen def1de
+	OM_uint32 maj_status, min_status;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	/*
Jakub Jelen def1de
+	 * Some GSSAPI implementations use the input value of ret_flags (an
Jakub Jelen def1de
+	 * output variable) as a means of triggering mechanism specific
Jakub Jelen def1de
+	 * features. Initializing it to zero avoids inadvertently
Jakub Jelen def1de
+	 * activating this non-standard behaviour.
Jakub Jelen def1de
+	 */
Jakub Jelen def1de
+
Jakub Jelen def1de
+	OM_uint32 ret_flags = 0;
Jakub Jelen def1de
+	gss_buffer_desc gssbuf, recv_tok, msg_tok;
Jakub Jelen def1de
+	gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
Jakub Jelen def1de
+	Gssctxt *ctxt = NULL;
Jakub Jelen def1de
+	struct sshbuf *shared_secret = NULL;
Jakub Jelen def1de
+	struct sshbuf *client_pubkey = NULL;
Jakub Jelen def1de
+	struct sshbuf *server_pubkey = NULL;
Jakub Jelen def1de
+	struct sshbuf *empty = sshbuf_new();
Jakub Jelen def1de
+	int type = 0;
Jakub Jelen def1de
+	gss_OID oid;
Jakub Jelen def1de
+	char *mechs;
Jakub Jelen def1de
+	u_char hash[SSH_DIGEST_MAX_LENGTH];
Jakub Jelen def1de
+	size_t hashlen;
Jakub Jelen def1de
+	int r;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	/* Initialise GSSAPI */
Jakub Jelen def1de
+
Jakub Jelen def1de
+	/* If we're rekeying, privsep means that some of the private structures
Jakub Jelen def1de
+	 * in the GSSAPI code are no longer available. This kludges them back
Jakub Jelen def1de
+	 * into life
Jakub Jelen def1de
+	 */
Jakub Jelen def1de
+	if (!ssh_gssapi_oid_table_ok()) {
Jakub Jelen def1de
+		mechs = ssh_gssapi_server_mechanisms();
Jakub Jelen def1de
+		free(mechs);
Jakub Jelen def1de
+	}
Jakub Jelen def1de
+
Jakub Jelen def1de
+	debug2("%s: Identifying %s", __func__, kex->name);
Jakub Jelen def1de
+	oid = ssh_gssapi_id_kex(NULL, kex->name, kex->kex_type);
Jakub Jelen def1de
+	if (oid == GSS_C_NO_OID)
Jakub Jelen def1de
+	   fatal("Unknown gssapi mechanism");
Jakub Jelen def1de
+
Jakub Jelen def1de
+	debug2("%s: Acquiring credentials", __func__);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, oid))))
Jakub Jelen def1de
+		fatal("Unable to acquire credentials for the server");
Jakub Jelen def1de
+
Jakub Jelen def1de
+	do {
Jakub Jelen def1de
+		debug("Wait SSH2_MSG_KEXGSS_INIT");
Jakub Jelen def1de
+		type = ssh_packet_read(ssh);
Jakub Jelen def1de
+		switch(type) {
Jakub Jelen def1de
+		case SSH2_MSG_KEXGSS_INIT:
Jakub Jelen def1de
+			if (client_pubkey != NULL)
Jakub Jelen def1de
+				fatal("Received KEXGSS_INIT after initialising");
Jakub Jelen def1de
+			if ((r = ssh_gssapi_sshpkt_get_buffer_desc(ssh,
Jakub Jelen def1de
+			        &recv_tok)) != 0 ||
Jakub Jelen def1de
+			    (r = sshpkt_getb_froms(ssh, &client_pubkey)) != 0 ||
Jakub Jelen def1de
+			    (r = sshpkt_get_end(ssh)) != 0)
Jakub Jelen def1de
+				fatal("sshpkt failed: %s", ssh_err(r));
Jakub Jelen def1de
+
Jakub Jelen def1de
+			switch (kex->kex_type) {
Jakub Jelen def1de
+			case KEX_GSS_GRP1_SHA1:
Jakub Jelen def1de
+			case KEX_GSS_GRP14_SHA1:
Jakub Jelen def1de
+			case KEX_GSS_GRP14_SHA256:
Jakub Jelen def1de
+			case KEX_GSS_GRP16_SHA512:
Jakub Jelen def1de
+				r = kex_dh_enc(kex, client_pubkey, &server_pubkey,
Jakub Jelen def1de
+				    &shared_secret);
Jakub Jelen def1de
+				break;
Jakub Jelen def1de
+			case KEX_GSS_NISTP256_SHA256:
Jakub Jelen def1de
+				r = kex_ecdh_enc(kex, client_pubkey, &server_pubkey,
Jakub Jelen def1de
+				    &shared_secret);
Jakub Jelen def1de
+				break;
Jakub Jelen def1de
+			case KEX_GSS_C25519_SHA256:
Jakub Jelen def1de
+				r = kex_c25519_enc(kex, client_pubkey, &server_pubkey,
Jakub Jelen def1de
+				    &shared_secret);
Jakub Jelen def1de
+				break;
Jakub Jelen def1de
+			default:
Jakub Jelen def1de
+				fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type);
Jakub Jelen def1de
+			}
Jakub Jelen def1de
+			if (r != 0)
Jakub Jelen def1de
+				goto out;
Jakub Jelen def1de
+
Jakub Jelen def1de
+			/* Send SSH_MSG_KEXGSS_HOSTKEY here, if we want */
Jakub Jelen def1de
+			break;
Jakub Jelen def1de
+		case SSH2_MSG_KEXGSS_CONTINUE:
Jakub Jelen def1de
+			if ((r = ssh_gssapi_sshpkt_get_buffer_desc(ssh,
Jakub Jelen def1de
+			        &recv_tok)) != 0 ||
Jakub Jelen def1de
+			    (r = sshpkt_get_end(ssh)) != 0)
Jakub Jelen def1de
+				fatal("sshpkt failed: %s", ssh_err(r));
Jakub Jelen def1de
+			break;
Jakub Jelen def1de
+		default:
Jakub Jelen def1de
+			sshpkt_disconnect(ssh,
Jakub Jelen def1de
+			    "Protocol error: didn't expect packet type %d",
Jakub Jelen def1de
+			    type);
Jakub Jelen def1de
+		}
Jakub Jelen def1de
+
Jakub Jelen def1de
+		maj_status = PRIVSEP(ssh_gssapi_accept_ctx(ctxt, &recv_tok,
Jakub Jelen def1de
+		    &send_tok, &ret_flags));
Jakub Jelen def1de
+
Jakub Jelen def1de
+		gss_release_buffer(&min_status, &recv_tok);
Jakub Jelen def1de
+
Jakub Jelen def1de
+		if (maj_status != GSS_S_COMPLETE && send_tok.length == 0)
Jakub Jelen def1de
+			fatal("Zero length token output when incomplete");
Jakub Jelen def1de
+
Jakub Jelen def1de
+		if (client_pubkey == NULL)
Jakub Jelen def1de
+			fatal("No client public key");
Jakub Jelen def1de
+
Jakub Jelen def1de
+		if (maj_status & GSS_S_CONTINUE_NEEDED) {
Jakub Jelen def1de
+			debug("Sending GSSAPI_CONTINUE");
Jakub Jelen def1de
+			if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_CONTINUE)) != 0 ||
Jakub Jelen def1de
+			    (r = sshpkt_put_string(ssh, send_tok.value, send_tok.length)) != 0 ||
Jakub Jelen def1de
+			    (r = sshpkt_send(ssh)) != 0)
Jakub Jelen def1de
+				fatal("sshpkt failed: %s", ssh_err(r));
Jakub Jelen def1de
+			gss_release_buffer(&min_status, &send_tok);
Jakub Jelen def1de
+		}
Jakub Jelen def1de
+	} while (maj_status & GSS_S_CONTINUE_NEEDED);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if (GSS_ERROR(maj_status)) {
Jakub Jelen def1de
+		if (send_tok.length > 0) {
Jakub Jelen def1de
+			if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_CONTINUE)) != 0 ||
Jakub Jelen def1de
+			    (r = sshpkt_put_string(ssh, send_tok.value, send_tok.length)) != 0 ||
Jakub Jelen def1de
+			    (r = sshpkt_send(ssh)) != 0)
Jakub Jelen def1de
+				fatal("sshpkt failed: %s", ssh_err(r));
Jakub Jelen def1de
+		}
Jakub Jelen def1de
+		fatal("accept_ctx died");
Jakub Jelen def1de
+	}
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if (!(ret_flags & GSS_C_MUTUAL_FLAG))
Jakub Jelen def1de
+		fatal("Mutual Authentication flag wasn't set");
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if (!(ret_flags & GSS_C_INTEG_FLAG))
Jakub Jelen def1de
+		fatal("Integrity flag wasn't set");
Jakub Jelen def1de
+
Jakub Jelen def1de
+	hashlen = sizeof(hash);
Jakub Jelen def1de
+	if ((r = kex_gen_hash(
Jakub Jelen def1de
+	    kex->hash_alg,
Jakub Jelen def1de
+	    kex->client_version,
Jakub Jelen def1de
+	    kex->server_version,
Jakub Jelen def1de
+	    kex->peer,
Jakub Jelen def1de
+	    kex->my,
Jakub Jelen def1de
+	    empty,
Jakub Jelen def1de
+	    client_pubkey,
Jakub Jelen def1de
+	    server_pubkey,
Jakub Jelen def1de
+	    shared_secret,
Jakub Jelen def1de
+	    hash, &hashlen)) != 0)
Jakub Jelen def1de
+		goto out;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	gssbuf.value = hash;
Jakub Jelen def1de
+	gssbuf.length = hashlen;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if (GSS_ERROR(PRIVSEP(ssh_gssapi_sign(ctxt, &gssbuf, &msg_tok))))
Jakub Jelen def1de
+		fatal("Couldn't get MIC");
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_COMPLETE)) != 0 ||
Jakub Jelen def1de
+	    (r = sshpkt_put_stringb(ssh, server_pubkey)) != 0 ||
Jakub Jelen def1de
+	    (r = sshpkt_put_string(ssh, msg_tok.value, msg_tok.length)) != 0)
Jakub Jelen def1de
+		fatal("sshpkt failed: %s", ssh_err(r));
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if (send_tok.length != 0) {
Jakub Jelen def1de
+		if ((r = sshpkt_put_u8(ssh, 1)) != 0 || /* true */
Jakub Jelen def1de
+		    (r = sshpkt_put_string(ssh, send_tok.value, send_tok.length)) != 0)
Jakub Jelen def1de
+			fatal("sshpkt failed: %s", ssh_err(r));
Jakub Jelen def1de
+	} else {
Jakub Jelen def1de
+		if ((r = sshpkt_put_u8(ssh, 0)) != 0) /* false */
Jakub Jelen def1de
+			fatal("sshpkt failed: %s", ssh_err(r));
Jakub Jelen def1de
+	}
Jakub Jelen def1de
+	if ((r = sshpkt_send(ssh)) != 0)
Jakub Jelen def1de
+		fatal("sshpkt_send failed: %s", ssh_err(r));
Jakub Jelen def1de
+
Jakub Jelen def1de
+	gss_release_buffer(&min_status, &send_tok);
Jakub Jelen def1de
+	gss_release_buffer(&min_status, &msg_tok);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if (gss_kex_context == NULL)
Jakub Jelen def1de
+		gss_kex_context = ctxt;
Jakub Jelen def1de
+	else
Jakub Jelen def1de
+		ssh_gssapi_delete_ctx(&ctxt);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if ((r = kex_derive_keys(ssh, hash, hashlen, shared_secret)) == 0)
Jakub Jelen def1de
+		r = kex_send_newkeys(ssh);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	/* If this was a rekey, then save out any delegated credentials we
Jakub Jelen def1de
+	 * just exchanged.  */
Jakub Jelen def1de
+	if (options.gss_store_rekey)
Jakub Jelen def1de
+		ssh_gssapi_rekey_creds();
Jakub Jelen def1de
+out:
Jakub Jelen def1de
+	sshbuf_free(empty);
Jakub Jelen def1de
+	explicit_bzero(hash, sizeof(hash));
Jakub Jelen def1de
+	sshbuf_free(shared_secret);
Jakub Jelen def1de
+	sshbuf_free(client_pubkey);
Jakub Jelen def1de
+	sshbuf_free(server_pubkey);
Jakub Jelen def1de
+	return r;
Jakub Jelen def1de
+}
Jakub Jelen def1de
+
Jakub Jelen def1de
+int
Jakub Jelen def1de
+kexgssgex_server(struct ssh *ssh)
Jakub Jelen def1de
+{
Jakub Jelen def1de
+	struct kex *kex = ssh->kex;
Jakub Jelen def1de
+	OM_uint32 maj_status, min_status;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	/*
Jakub Jelen def1de
+	 * Some GSSAPI implementations use the input value of ret_flags (an
Jakub Jelen def1de
+	 * output variable) as a means of triggering mechanism specific
Jakub Jelen def1de
+	 * features. Initializing it to zero avoids inadvertently
Jakub Jelen def1de
+	 * activating this non-standard behaviour.
Jakub Jelen def1de
+	 */
Jakub Jelen def1de
+
Jakub Jelen def1de
+	OM_uint32 ret_flags = 0;
Jakub Jelen def1de
+	gss_buffer_desc gssbuf, recv_tok, msg_tok;
Jakub Jelen def1de
+	gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
Jakub Jelen def1de
+	Gssctxt *ctxt = NULL;
Jakub Jelen def1de
+	struct sshbuf *shared_secret = NULL;
Jakub Jelen def1de
+	int type = 0;
Jakub Jelen def1de
+	gss_OID oid;
Jakub Jelen def1de
+	char *mechs;
Jakub Jelen def1de
+	u_char hash[SSH_DIGEST_MAX_LENGTH];
Jakub Jelen def1de
+	size_t hashlen;
Jakub Jelen def1de
+	BIGNUM *dh_client_pub = NULL;
Jakub Jelen def1de
+	const BIGNUM *pub_key, *dh_p, *dh_g;
Jakub Jelen def1de
+	int min = -1, max = -1, nbits = -1;
Jakub Jelen def1de
+	int cmin = -1, cmax = -1; /* client proposal */
Jakub Jelen def1de
+	struct sshbuf *empty = sshbuf_new();
Jakub Jelen def1de
+	int r;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	/* Initialise GSSAPI */
Jakub Jelen def1de
+
Jakub Jelen def1de
+	/* If we're rekeying, privsep means that some of the private structures
Jakub Jelen def1de
+	 * in the GSSAPI code are no longer available. This kludges them back
Jakub Jelen def1de
+	 * into life
Jakub Jelen def1de
+	 */
Jakub Jelen def1de
+	if (!ssh_gssapi_oid_table_ok())
Jakub Jelen def1de
+		if ((mechs = ssh_gssapi_server_mechanisms()))
Jakub Jelen def1de
+			free(mechs);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	debug2("%s: Identifying %s", __func__, kex->name);
Jakub Jelen def1de
+	oid = ssh_gssapi_id_kex(NULL, kex->name, kex->kex_type);
Jakub Jelen def1de
+	if (oid == GSS_C_NO_OID)
Jakub Jelen def1de
+	   fatal("Unknown gssapi mechanism");
Jakub Jelen def1de
+
Jakub Jelen def1de
+	debug2("%s: Acquiring credentials", __func__);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, oid))))
Jakub Jelen def1de
+		fatal("Unable to acquire credentials for the server");
Jakub Jelen def1de
+
Jakub Jelen def1de
+	/* 5. S generates an ephemeral key pair (do the allocations early) */
Jakub Jelen def1de
+	debug("Doing group exchange");
Jakub Jelen def1de
+	ssh_packet_read_expect(ssh, SSH2_MSG_KEXGSS_GROUPREQ);
Jakub Jelen def1de
+	/* store client proposal to provide valid signature */
Jakub Jelen def1de
+	if ((r = sshpkt_get_u32(ssh, &cmin)) != 0 ||
Jakub Jelen def1de
+	    (r = sshpkt_get_u32(ssh, &nbits)) != 0 ||
Jakub Jelen def1de
+	    (r = sshpkt_get_u32(ssh, &cmax)) != 0 ||
Jakub Jelen def1de
+	    (r = sshpkt_get_end(ssh)) != 0)
Jakub Jelen def1de
+		fatal("sshpkt failed: %s", ssh_err(r));
Jakub Jelen def1de
+	kex->nbits = nbits;
Jakub Jelen def1de
+	kex->min = cmin;
Jakub Jelen def1de
+	kex->max = cmax;
Jakub Jelen def1de
+	min = MAX(DH_GRP_MIN, cmin);
Jakub Jelen def1de
+	max = MIN(DH_GRP_MAX, cmax);
Jakub Jelen def1de
+	nbits = MAXIMUM(DH_GRP_MIN, nbits);
Jakub Jelen def1de
+	nbits = MINIMUM(DH_GRP_MAX, nbits);
Jakub Jelen def1de
+	if (max < min || nbits < min || max < nbits)
Jakub Jelen def1de
+		fatal("GSS_GEX, bad parameters: %d !< %d !< %d",
Jakub Jelen def1de
+		    min, nbits, max);
Jakub Jelen def1de
+	kex->dh = PRIVSEP(choose_dh(min, nbits, max));
Jakub Jelen def1de
+	if (kex->dh == NULL) {
Jakub Jelen def1de
+		sshpkt_disconnect(ssh, "Protocol error: no matching group found");
Jakub Jelen def1de
+		fatal("Protocol error: no matching group found");
Jakub Jelen def1de
+	}
Jakub Jelen def1de
+
Jakub Jelen def1de
+	DH_get0_pqg(kex->dh, &dh_p, NULL, &dh_g);
Jakub Jelen def1de
+	if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_GROUP)) != 0 ||
Jakub Jelen def1de
+	    (r = sshpkt_put_bignum2(ssh, dh_p)) != 0 ||
Jakub Jelen def1de
+	    (r = sshpkt_put_bignum2(ssh, dh_g)) != 0 ||
Jakub Jelen def1de
+	    (r = sshpkt_send(ssh)) != 0)
Jakub Jelen def1de
+		fatal("sshpkt failed: %s", ssh_err(r));
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if ((r = ssh_packet_write_wait(ssh)) != 0)
Jakub Jelen def1de
+		fatal("ssh_packet_write_wait: %s", ssh_err(r));
Jakub Jelen def1de
+
Jakub Jelen def1de
+	/* Compute our exchange value in parallel with the client */
Jakub Jelen def1de
+	if ((r = dh_gen_key(kex->dh, kex->we_need * 8)) != 0)
Jakub Jelen def1de
+		goto out;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	do {
Jakub Jelen def1de
+		debug("Wait SSH2_MSG_GSSAPI_INIT");
Jakub Jelen def1de
+		type = ssh_packet_read(ssh);
Jakub Jelen def1de
+		switch(type) {
Jakub Jelen def1de
+		case SSH2_MSG_KEXGSS_INIT:
Jakub Jelen def1de
+			if (dh_client_pub != NULL)
Jakub Jelen def1de
+				fatal("Received KEXGSS_INIT after initialising");
Jakub Jelen def1de
+			if ((r = ssh_gssapi_sshpkt_get_buffer_desc(ssh,
Jakub Jelen def1de
+			        &recv_tok)) != 0 ||
Jakub Jelen def1de
+			    (r = sshpkt_get_bignum2(ssh, &dh_client_pub)) != 0 ||
Jakub Jelen def1de
+			    (r = sshpkt_get_end(ssh)) != 0)
Jakub Jelen def1de
+				fatal("sshpkt failed: %s", ssh_err(r));
Jakub Jelen def1de
+
Jakub Jelen def1de
+			/* Send SSH_MSG_KEXGSS_HOSTKEY here, if we want */
Jakub Jelen def1de
+			break;
Jakub Jelen def1de
+		case SSH2_MSG_KEXGSS_CONTINUE:
Jakub Jelen def1de
+			if ((r = ssh_gssapi_sshpkt_get_buffer_desc(ssh,
Jakub Jelen def1de
+			        &recv_tok)) != 0 ||
Jakub Jelen def1de
+			    (r = sshpkt_get_end(ssh)) != 0)
Jakub Jelen def1de
+				fatal("sshpkt failed: %s", ssh_err(r));
Jakub Jelen def1de
+			break;
Jakub Jelen def1de
+		default:
Jakub Jelen def1de
+			sshpkt_disconnect(ssh,
Jakub Jelen def1de
+			    "Protocol error: didn't expect packet type %d",
Jakub Jelen def1de
+			    type);
Jakub Jelen def1de
+		}
Jakub Jelen def1de
+
Jakub Jelen def1de
+		maj_status = PRIVSEP(ssh_gssapi_accept_ctx(ctxt, &recv_tok,
Jakub Jelen def1de
+		    &send_tok, &ret_flags));
Jakub Jelen def1de
+
Jakub Jelen def1de
+		gss_release_buffer(&min_status, &recv_tok);
Jakub Jelen def1de
+
Jakub Jelen def1de
+		if (maj_status != GSS_S_COMPLETE && send_tok.length == 0)
Jakub Jelen def1de
+			fatal("Zero length token output when incomplete");
Jakub Jelen def1de
+
Jakub Jelen def1de
+		if (dh_client_pub == NULL)
Jakub Jelen def1de
+			fatal("No client public key");
Jakub Jelen def1de
+
Jakub Jelen def1de
+		if (maj_status & GSS_S_CONTINUE_NEEDED) {
Jakub Jelen def1de
+			debug("Sending GSSAPI_CONTINUE");
Jakub Jelen def1de
+			if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_CONTINUE)) != 0 ||
Jakub Jelen def1de
+			    (r = sshpkt_put_string(ssh, send_tok.value, send_tok.length)) != 0 ||
Jakub Jelen def1de
+			    (r = sshpkt_send(ssh)) != 0)
Jakub Jelen def1de
+				fatal("sshpkt failed: %s", ssh_err(r));
Jakub Jelen def1de
+			gss_release_buffer(&min_status, &send_tok);
Jakub Jelen def1de
+		}
Jakub Jelen def1de
+	} while (maj_status & GSS_S_CONTINUE_NEEDED);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if (GSS_ERROR(maj_status)) {
Jakub Jelen def1de
+		if (send_tok.length > 0) {
Jakub Jelen def1de
+			if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_CONTINUE)) != 0 ||
Jakub Jelen def1de
+			    (r = sshpkt_put_string(ssh, send_tok.value, send_tok.length)) != 0 ||
Jakub Jelen def1de
+			    (r = sshpkt_send(ssh)) != 0)
Jakub Jelen def1de
+				fatal("sshpkt failed: %s", ssh_err(r));
Jakub Jelen def1de
+		}
Jakub Jelen def1de
+		fatal("accept_ctx died");
Jakub Jelen def1de
+	}
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if (!(ret_flags & GSS_C_MUTUAL_FLAG))
Jakub Jelen def1de
+		fatal("Mutual Authentication flag wasn't set");
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if (!(ret_flags & GSS_C_INTEG_FLAG))
Jakub Jelen def1de
+		fatal("Integrity flag wasn't set");
Jakub Jelen def1de
+
Jakub Jelen def1de
+	/* calculate shared secret */
Jakub Jelen def1de
+	if ((shared_secret = sshbuf_new()) == NULL) {
Jakub Jelen def1de
+		r = SSH_ERR_ALLOC_FAIL;
Jakub Jelen def1de
+		goto out;
Jakub Jelen def1de
+	}
Jakub Jelen def1de
+	if ((r = kex_dh_compute_key(kex, dh_client_pub, shared_secret)) != 0)
Jakub Jelen def1de
+		goto out;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	DH_get0_key(kex->dh, &pub_key, NULL);
Jakub Jelen def1de
+	DH_get0_pqg(kex->dh, &dh_p, NULL, &dh_g);
Jakub Jelen def1de
+	hashlen = sizeof(hash);
Jakub Jelen def1de
+	if ((r = kexgex_hash(
Jakub Jelen def1de
+	    kex->hash_alg,
Jakub Jelen def1de
+	    kex->client_version,
Jakub Jelen def1de
+	    kex->server_version,
Jakub Jelen def1de
+	    kex->peer,
Jakub Jelen def1de
+	    kex->my,
Jakub Jelen def1de
+	    empty,
Jakub Jelen def1de
+	    cmin, nbits, cmax,
Jakub Jelen def1de
+	    dh_p, dh_g,
Jakub Jelen def1de
+	    dh_client_pub,
Jakub Jelen def1de
+	    pub_key,
Jakub Jelen def1de
+	    sshbuf_ptr(shared_secret), sshbuf_len(shared_secret),
Jakub Jelen def1de
+	    hash, &hashlen)) != 0)
Jakub Jelen def1de
+		fatal("kexgex_hash failed: %s", ssh_err(r));
Jakub Jelen def1de
+
Jakub Jelen def1de
+	gssbuf.value = hash;
Jakub Jelen def1de
+	gssbuf.length = hashlen;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if (GSS_ERROR(PRIVSEP(ssh_gssapi_sign(ctxt, &gssbuf, &msg_tok))))
Jakub Jelen def1de
+		fatal("Couldn't get MIC");
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_COMPLETE)) != 0 ||
Jakub Jelen def1de
+	    (r = sshpkt_put_bignum2(ssh, pub_key)) != 0 ||
Jakub Jelen def1de
+	    (r = sshpkt_put_string(ssh, msg_tok.value, msg_tok.length)) != 0)
Jakub Jelen def1de
+		fatal("sshpkt failed: %s", ssh_err(r));
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if (send_tok.length != 0) {
Jakub Jelen def1de
+		if ((r = sshpkt_put_u8(ssh, 1)) != 0 || /* true */
Jakub Jelen def1de
+		    (r = sshpkt_put_string(ssh, send_tok.value, send_tok.length)) != 0)
Jakub Jelen def1de
+			fatal("sshpkt failed: %s", ssh_err(r));
Jakub Jelen def1de
+	} else {
Jakub Jelen def1de
+		if ((r = sshpkt_put_u8(ssh, 0)) != 0) /* false */
Jakub Jelen def1de
+			fatal("sshpkt failed: %s", ssh_err(r));
Jakub Jelen def1de
+	}
Jakub Jelen def1de
+	if ((r = sshpkt_send(ssh)) != 0)
Jakub Jelen def1de
+		fatal("sshpkt failed: %s", ssh_err(r));
Jakub Jelen def1de
+
Jakub Jelen def1de
+	gss_release_buffer(&min_status, &send_tok);
Jakub Jelen def1de
+	gss_release_buffer(&min_status, &msg_tok);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if (gss_kex_context == NULL)
Jakub Jelen def1de
+		gss_kex_context = ctxt;
Jakub Jelen def1de
+	else
Jakub Jelen def1de
+		ssh_gssapi_delete_ctx(&ctxt);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	/* Finally derive the keys and send them */
Jakub Jelen def1de
+	if ((r = kex_derive_keys(ssh, hash, hashlen, shared_secret)) == 0)
Jakub Jelen def1de
+		r = kex_send_newkeys(ssh);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	/* If this was a rekey, then save out any delegated credentials we
Jakub Jelen def1de
+	 * just exchanged.  */
Jakub Jelen def1de
+	if (options.gss_store_rekey)
Jakub Jelen def1de
+		ssh_gssapi_rekey_creds();
Jakub Jelen def1de
+out:
Jakub Jelen def1de
+	sshbuf_free(empty);
Jakub Jelen def1de
+	explicit_bzero(hash, sizeof(hash));
Jakub Jelen def1de
+	DH_free(kex->dh);
Jakub Jelen def1de
+	kex->dh = NULL;
Jakub Jelen def1de
+	BN_clear_free(dh_client_pub);
Jakub Jelen def1de
+	sshbuf_free(shared_secret);
Jakub Jelen def1de
+	return r;
Jakub Jelen def1de
+}
Jakub Jelen def1de
+#endif /* defined(GSSAPI) && defined(WITH_OPENSSL) */
Jakub Jelen def1de
diff --git a/monitor.c b/monitor.c
Jakub Jelen 51f5c1
index 2ce89fe9..ebf76c7f 100644
Jakub Jelen def1de
--- a/monitor.c
Jakub Jelen def1de
+++ b/monitor.c
Jakub Jelen 51f5c1
@@ -148,6 +148,8 @@ int mm_answer_gss_setup_ctx(struct ssh *, int, struct sshbuf *);
Jakub Jelen def1de
 int mm_answer_gss_accept_ctx(struct ssh *, int, struct sshbuf *);
Jakub Jelen def1de
 int mm_answer_gss_userok(struct ssh *, int, struct sshbuf *);
Jakub Jelen def1de
 int mm_answer_gss_checkmic(struct ssh *, int, struct sshbuf *);
Jakub Jelen 51f5c1
+int mm_answer_gss_sign(struct ssh *, int, struct sshbuf *);
Jakub Jelen 51f5c1
+int mm_answer_gss_updatecreds(struct ssh *, int, struct sshbuf *);
Jakub Jelen def1de
 #endif
Jakub Jelen def1de
 
Jakub Jelen def1de
 #ifdef SSH_AUDIT_EVENTS
Jakub Jelen 51f5c1
@@ -220,11 +222,18 @@ struct mon_table mon_dispatch_proto20[] = {
Jakub Jelen def1de
     {MONITOR_REQ_GSSSTEP, 0, mm_answer_gss_accept_ctx},
Jakub Jelen def1de
     {MONITOR_REQ_GSSUSEROK, MON_ONCE|MON_AUTHDECIDE, mm_answer_gss_userok},
Jakub Jelen def1de
     {MONITOR_REQ_GSSCHECKMIC, MON_ONCE, mm_answer_gss_checkmic},
Jakub Jelen def1de
+    {MONITOR_REQ_GSSSIGN, MON_ONCE, mm_answer_gss_sign},
Jakub Jelen def1de
 #endif
Jakub Jelen def1de
     {0, 0, NULL}
Jakub Jelen def1de
 };
Jakub Jelen def1de
 
Jakub Jelen def1de
 struct mon_table mon_dispatch_postauth20[] = {
Jakub Jelen def1de
+#ifdef GSSAPI
Jakub Jelen def1de
+    {MONITOR_REQ_GSSSETUP, 0, mm_answer_gss_setup_ctx},
Jakub Jelen def1de
+    {MONITOR_REQ_GSSSTEP, 0, mm_answer_gss_accept_ctx},
Jakub Jelen def1de
+    {MONITOR_REQ_GSSSIGN, 0, mm_answer_gss_sign},
Jakub Jelen def1de
+    {MONITOR_REQ_GSSUPCREDS, 0, mm_answer_gss_updatecreds},
Jakub Jelen def1de
+#endif
Jakub Jelen def1de
 #ifdef WITH_OPENSSL
Jakub Jelen def1de
     {MONITOR_REQ_MODULI, 0, mm_answer_moduli},
Jakub Jelen def1de
 #endif
Jakub Jelen 51f5c1
@@ -293,6 +302,10 @@ monitor_child_preauth(struct ssh *ssh, struct monitor *pmonitor)
Jakub Jelen def1de
 	/* Permit requests for moduli and signatures */
Jakub Jelen def1de
 	monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1);
Jakub Jelen def1de
 	monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1);
Jakub Jelen def1de
+#ifdef GSSAPI
Jakub Jelen def1de
+	/* and for the GSSAPI key exchange */
Jakub Jelen def1de
+	monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1);
Jakub Jelen def1de
+#endif
Jakub Jelen def1de
 
Jakub Jelen def1de
 	/* The first few requests do not require asynchronous access */
Jakub Jelen def1de
 	while (!authenticated) {
Jakub Jelen 51f5c1
@@ -406,6 +419,10 @@ monitor_child_postauth(struct ssh *ssh, struct monitor *pmonitor)
Jakub Jelen def1de
 	monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1);
Jakub Jelen def1de
 	monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1);
Jakub Jelen def1de
 	monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1);
Jakub Jelen def1de
+#ifdef GSSAPI
Jakub Jelen def1de
+	/* and for the GSSAPI key exchange */
Jakub Jelen def1de
+	monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1);
Jakub Jelen def1de
+#endif
Jakub Jelen def1de
 
Jakub Jelen def1de
 	if (auth_opts->permit_pty_flag) {
Jakub Jelen def1de
 		monitor_permit(mon_dispatch, MONITOR_REQ_PTY, 1);
Jakub Jelen 51f5c1
@@ -1713,6 +1730,17 @@ monitor_apply_keystate(struct ssh *ssh, struct monitor *pmonitor)
Jakub Jelen def1de
 # ifdef OPENSSL_HAS_ECC
Jakub Jelen def1de
 		kex->kex[KEX_ECDH_SHA2] = kex_gen_server;
Jakub Jelen def1de
 # endif
Jakub Jelen def1de
+# ifdef GSSAPI
Jakub Jelen def1de
+		if (options.gss_keyex) {
Jakub Jelen def1de
+			kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server;
Jakub Jelen def1de
+			kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_server;
Jakub Jelen def1de
+			kex->kex[KEX_GSS_GRP14_SHA256] = kexgss_server;
Jakub Jelen def1de
+			kex->kex[KEX_GSS_GRP16_SHA512] = kexgss_server;
Jakub Jelen def1de
+			kex->kex[KEX_GSS_GEX_SHA1] = kexgssgex_server;
Jakub Jelen def1de
+			kex->kex[KEX_GSS_NISTP256_SHA256] = kexgss_server;
Jakub Jelen def1de
+			kex->kex[KEX_GSS_C25519_SHA256] = kexgss_server;
Jakub Jelen def1de
+		}
Jakub Jelen def1de
+# endif
Jakub Jelen def1de
 #endif /* WITH_OPENSSL */
Jakub Jelen def1de
 		kex->kex[KEX_C25519_SHA256] = kex_gen_server;
Jakub Jelen def1de
 		kex->kex[KEX_KEM_SNTRUP4591761X25519_SHA512] = kex_gen_server;
Jakub Jelen 51f5c1
@@ -1806,8 +1834,8 @@ mm_answer_gss_setup_ctx(struct ssh *ssh, int sock, struct sshbuf *m)
Jakub Jelen def1de
 	u_char *p;
Jakub Jelen def1de
 	int r;
Jakub Jelen def1de
 
Jakub Jelen def1de
-	if (!options.gss_authentication)
Jakub Jelen def1de
-		fatal("%s: GSSAPI authentication not enabled", __func__);
Jakub Jelen def1de
+	if (!options.gss_authentication && !options.gss_keyex)
Jakub Jelen def1de
+		fatal("%s: GSSAPI not enabled", __func__);
Jakub Jelen def1de
 
Jakub Jelen def1de
 	if ((r = sshbuf_get_string(m, &p, &len)) != 0)
Jakub Jelen def1de
 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
Jakub Jelen 51f5c1
@@ -1839,8 +1867,8 @@ mm_answer_gss_accept_ctx(struct ssh *ssh, int sock, struct sshbuf *m)
Jakub Jelen def1de
 	OM_uint32 flags = 0; /* GSI needs this */
Jakub Jelen def1de
 	int r;
Jakub Jelen def1de
 
Jakub Jelen def1de
-	if (!options.gss_authentication)
Jakub Jelen def1de
-		fatal("%s: GSSAPI authentication not enabled", __func__);
Jakub Jelen def1de
+	if (!options.gss_authentication && !options.gss_keyex)
Jakub Jelen def1de
+		fatal("%s: GSSAPI not enabled", __func__);
Jakub Jelen def1de
 
Jakub Jelen def1de
 	if ((r = ssh_gssapi_get_buffer_desc(m, &in)) != 0)
Jakub Jelen def1de
 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
Jakub Jelen 51f5c1
@@ -1860,6 +1888,7 @@ mm_answer_gss_accept_ctx(struct ssh *ssh, int sock, struct sshbuf *m)
Jakub Jelen def1de
 		monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 0);
Jakub Jelen def1de
 		monitor_permit(mon_dispatch, MONITOR_REQ_GSSUSEROK, 1);
Jakub Jelen def1de
 		monitor_permit(mon_dispatch, MONITOR_REQ_GSSCHECKMIC, 1);
Jakub Jelen def1de
+		monitor_permit(mon_dispatch, MONITOR_REQ_GSSSIGN, 1);
Jakub Jelen def1de
 	}
Jakub Jelen def1de
 	return (0);
Jakub Jelen def1de
 }
Jakub Jelen 51f5c1
@@ -1871,8 +1900,8 @@ mm_answer_gss_checkmic(struct ssh *ssh, int sock, struct sshbuf *m)
Jakub Jelen def1de
 	OM_uint32 ret;
Jakub Jelen def1de
 	int r;
Jakub Jelen def1de
 
Jakub Jelen def1de
-	if (!options.gss_authentication)
Jakub Jelen def1de
-		fatal("%s: GSSAPI authentication not enabled", __func__);
Jakub Jelen def1de
+	if (!options.gss_authentication && !options.gss_keyex)
Jakub Jelen def1de
+		fatal("%s: GSSAPI not enabled", __func__);
Jakub Jelen def1de
 
Jakub Jelen def1de
 	if ((r = ssh_gssapi_get_buffer_desc(m, &gssbuf)) != 0 ||
Jakub Jelen def1de
 	    (r = ssh_gssapi_get_buffer_desc(m, &mic)) != 0)
Jakub Jelen 51f5c1
@@ -1898,13 +1927,17 @@ mm_answer_gss_checkmic(struct ssh *ssh, int sock, struct sshbuf *m)
Jakub Jelen def1de
 int
Jakub Jelen def1de
 mm_answer_gss_userok(struct ssh *ssh, int sock, struct sshbuf *m)
Jakub Jelen def1de
 {
Jakub Jelen def1de
-	int r, authenticated;
Jakub Jelen def1de
+	int r, authenticated, kex;
Jakub Jelen def1de
 	const char *displayname;
Jakub Jelen def1de
 
Jakub Jelen def1de
-	if (!options.gss_authentication)
Jakub Jelen def1de
-		fatal("%s: GSSAPI authentication not enabled", __func__);
Jakub Jelen def1de
+	if (!options.gss_authentication && !options.gss_keyex)
Jakub Jelen def1de
+		fatal("%s: GSSAPI not enabled", __func__);
Jakub Jelen def1de
 
Jakub Jelen def1de
-	authenticated = authctxt->valid && ssh_gssapi_userok(authctxt->user);
Jakub Jelen def1de
+	if ((r = sshbuf_get_u32(m, &kex)) != 0)
Jakub Jelen def1de
+		fatal("%s: buffer error: %s", __func__, ssh_err(r));
Jakub Jelen def1de
+
Jakub Jelen def1de
+	authenticated = authctxt->valid &&
Jakub Jelen def1de
+	    ssh_gssapi_userok(authctxt->user, authctxt->pw, kex);
Jakub Jelen def1de
 
Jakub Jelen def1de
 	sshbuf_reset(m);
Jakub Jelen def1de
 	if ((r = sshbuf_put_u32(m, authenticated)) != 0)
Jakub Jelen 51f5c1
@@ -1913,7 +1946,11 @@ mm_answer_gss_userok(struct ssh *ssh, int sock, struct sshbuf *m)
Jakub Jelen def1de
 	debug3("%s: sending result %d", __func__, authenticated);
Jakub Jelen def1de
 	mm_request_send(sock, MONITOR_ANS_GSSUSEROK, m);
Jakub Jelen def1de
 
Jakub Jelen def1de
-	auth_method = "gssapi-with-mic";
Jakub Jelen def1de
+	if (kex) {
Jakub Jelen def1de
+		auth_method = "gssapi-keyex";
Jakub Jelen def1de
+	} else {
Jakub Jelen def1de
+		auth_method = "gssapi-with-mic";
Jakub Jelen def1de
+	}
Jakub Jelen def1de
 
Jakub Jelen def1de
 	if ((displayname = ssh_gssapi_displayname()) != NULL)
Jakub Jelen def1de
 		auth2_record_info(authctxt, "%s", displayname);
Jakub Jelen 51f5c1
@@ -1921,5 +1958,85 @@ mm_answer_gss_userok(struct ssh *ssh, int sock, struct sshbuf *m)
Jakub Jelen def1de
 	/* Monitor loop will terminate if authenticated */
Jakub Jelen def1de
 	return (authenticated);
Jakub Jelen def1de
 }
Jakub Jelen def1de
+
Jakub Jelen def1de
+int
Jakub Jelen def1de
+mm_answer_gss_sign(struct ssh *ssh, int socket, struct sshbuf *m)
Jakub Jelen def1de
+{
Jakub Jelen def1de
+	gss_buffer_desc data;
Jakub Jelen def1de
+	gss_buffer_desc hash = GSS_C_EMPTY_BUFFER;
Jakub Jelen def1de
+	OM_uint32 major, minor;
Jakub Jelen def1de
+	size_t len;
Jakub Jelen def1de
+	u_char *p = NULL;
Jakub Jelen def1de
+	int r;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if (!options.gss_authentication && !options.gss_keyex)
Jakub Jelen def1de
+		fatal("%s: GSSAPI not enabled", __func__);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if ((r = sshbuf_get_string(m, &p, &len)) != 0)
Jakub Jelen def1de
+		fatal("%s: buffer error: %s", __func__, ssh_err(r));
Jakub Jelen def1de
+	data.value = p;
Jakub Jelen def1de
+	data.length = len;
Jakub Jelen def1de
+	/* Lengths of SHA-1, SHA-256 and SHA-512 hashes that are used */
Jakub Jelen def1de
+	if (data.length != 20 && data.length != 32 && data.length != 64)
Jakub Jelen def1de
+		fatal("%s: data length incorrect: %d", __func__,
Jakub Jelen def1de
+		    (int) data.length);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	/* Save the session ID on the first time around */
Jakub Jelen def1de
+	if (session_id2_len == 0) {
Jakub Jelen def1de
+		session_id2_len = data.length;
Jakub Jelen def1de
+		session_id2 = xmalloc(session_id2_len);
Jakub Jelen def1de
+		memcpy(session_id2, data.value, session_id2_len);
Jakub Jelen def1de
+	}
Jakub Jelen def1de
+	major = ssh_gssapi_sign(gsscontext, &data, &hash);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	free(data.value);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	sshbuf_reset(m);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if ((r = sshbuf_put_u32(m, major)) != 0 ||
Jakub Jelen def1de
+	    (r = sshbuf_put_string(m, hash.value, hash.length)) != 0)
Jakub Jelen def1de
+		fatal("%s: buffer error: %s", __func__, ssh_err(r));
Jakub Jelen def1de
+
Jakub Jelen def1de
+	mm_request_send(socket, MONITOR_ANS_GSSSIGN, m);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	gss_release_buffer(&minor, &hash);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	/* Turn on getpwnam permissions */
Jakub Jelen def1de
+	monitor_permit(mon_dispatch, MONITOR_REQ_PWNAM, 1);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	/* And credential updating, for when rekeying */
Jakub Jelen def1de
+	monitor_permit(mon_dispatch, MONITOR_REQ_GSSUPCREDS, 1);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	return (0);
Jakub Jelen def1de
+}
Jakub Jelen def1de
+
Jakub Jelen def1de
+int
Jakub Jelen def1de
+mm_answer_gss_updatecreds(struct ssh *ssh, int socket, struct sshbuf *m) {
Jakub Jelen def1de
+	ssh_gssapi_ccache store;
Jakub Jelen def1de
+	int r, ok;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if (!options.gss_authentication && !options.gss_keyex)
Jakub Jelen def1de
+		fatal("%s: GSSAPI not enabled", __func__);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if ((r = sshbuf_get_string(m, (u_char **)&store.filename, NULL)) != 0 ||
Jakub Jelen def1de
+	    (r = sshbuf_get_string(m, (u_char **)&store.envvar, NULL)) != 0 ||
Jakub Jelen def1de
+	    (r = sshbuf_get_string(m, (u_char **)&store.envval, NULL)) != 0)
Jakub Jelen def1de
+		fatal("%s: buffer error: %s", __func__, ssh_err(r));
Jakub Jelen def1de
+
Jakub Jelen def1de
+	ok = ssh_gssapi_update_creds(&store);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	free(store.filename);
Jakub Jelen def1de
+	free(store.envvar);
Jakub Jelen def1de
+	free(store.envval);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	sshbuf_reset(m);
Jakub Jelen def1de
+	if ((r = sshbuf_put_u32(m, ok)) != 0)
Jakub Jelen def1de
+		fatal("%s: buffer error: %s", __func__, ssh_err(r));
Jakub Jelen def1de
+
Jakub Jelen def1de
+	mm_request_send(socket, MONITOR_ANS_GSSUPCREDS, m);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	return(0);
Jakub Jelen def1de
+}
Jakub Jelen def1de
+
Jakub Jelen def1de
 #endif /* GSSAPI */
Jakub Jelen def1de
 
Jakub Jelen def1de
diff --git a/monitor.h b/monitor.h
Jakub Jelen def1de
index 683e5e07..2b1a2d59 100644
Jakub Jelen def1de
--- a/monitor.h
Jakub Jelen def1de
+++ b/monitor.h
Jakub Jelen def1de
@@ -63,6 +63,8 @@ enum monitor_reqtype {
Jakub Jelen def1de
 	MONITOR_REQ_PAM_FREE_CTX = 110, MONITOR_ANS_PAM_FREE_CTX = 111,
Jakub Jelen def1de
 	MONITOR_REQ_AUDIT_EVENT = 112, MONITOR_REQ_AUDIT_COMMAND = 113,
Jakub Jelen def1de
 
Jakub Jelen def1de
+	MONITOR_REQ_GSSSIGN = 150, MONITOR_ANS_GSSSIGN = 151,
Jakub Jelen def1de
+	MONITOR_REQ_GSSUPCREDS = 152, MONITOR_ANS_GSSUPCREDS = 153,
Jakub Jelen def1de
 };
Jakub Jelen def1de
 
Jakub Jelen def1de
 struct ssh;
Jakub Jelen def1de
diff --git a/monitor_wrap.c b/monitor_wrap.c
Jakub Jelen 51f5c1
index 001a8fa1..6edb509a 100644
Jakub Jelen def1de
--- a/monitor_wrap.c
Jakub Jelen def1de
+++ b/monitor_wrap.c
Jakub Jelen 51f5c1
@@ -993,13 +993,15 @@ mm_ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic)
Jakub Jelen def1de
 }
Jakub Jelen def1de
 
Jakub Jelen def1de
 int
Jakub Jelen def1de
-mm_ssh_gssapi_userok(char *user)
Jakub Jelen def1de
+mm_ssh_gssapi_userok(char *user, struct passwd *pw, int kex)
Jakub Jelen def1de
 {
Jakub Jelen def1de
 	struct sshbuf *m;
Jakub Jelen def1de
 	int r, authenticated = 0;
Jakub Jelen def1de
 
Jakub Jelen def1de
 	if ((m = sshbuf_new()) == NULL)
Jakub Jelen def1de
 		fatal("%s: sshbuf_new failed", __func__);
Jakub Jelen def1de
+	if ((r = sshbuf_put_u32(m, kex)) != 0)
Jakub Jelen def1de
+		fatal("%s: buffer error: %s", __func__, ssh_err(r));
Jakub Jelen def1de
 
Jakub Jelen def1de
 	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSUSEROK, m);
Jakub Jelen def1de
 	mm_request_receive_expect(pmonitor->m_recvfd,
Jakub Jelen 51f5c1
@@ -1012,4 +1014,57 @@ mm_ssh_gssapi_userok(char *user)
Jakub Jelen def1de
 	debug3("%s: user %sauthenticated",__func__, authenticated ? "" : "not ");
Jakub Jelen def1de
 	return (authenticated);
Jakub Jelen def1de
 }
Jakub Jelen def1de
+
Jakub Jelen def1de
+OM_uint32
Jakub Jelen def1de
+mm_ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_desc *data, gss_buffer_desc *hash)
Jakub Jelen def1de
+{
Jakub Jelen def1de
+	struct sshbuf *m;
Jakub Jelen def1de
+	OM_uint32 major;
Jakub Jelen def1de
+	int r;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if ((m = sshbuf_new()) == NULL)
Jakub Jelen def1de
+		fatal("%s: sshbuf_new failed", __func__);
Jakub Jelen def1de
+	if ((r = sshbuf_put_string(m, data->value, data->length)) != 0)
Jakub Jelen def1de
+		fatal("%s: buffer error: %s", __func__, ssh_err(r));
Jakub Jelen def1de
+
Jakub Jelen def1de
+	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSSIGN, m);
Jakub Jelen def1de
+	mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSSIGN, m);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if ((r = sshbuf_get_u32(m, &major)) != 0 ||
Jakub Jelen def1de
+	    (r = ssh_gssapi_get_buffer_desc(m, hash)) != 0)
Jakub Jelen def1de
+		fatal("%s: buffer error: %s", __func__, ssh_err(r));
Jakub Jelen def1de
+
Jakub Jelen def1de
+	sshbuf_free(m);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	return (major);
Jakub Jelen def1de
+}
Jakub Jelen def1de
+
Jakub Jelen def1de
+int
Jakub Jelen def1de
+mm_ssh_gssapi_update_creds(ssh_gssapi_ccache *store)
Jakub Jelen def1de
+{
Jakub Jelen def1de
+	struct sshbuf *m;
Jakub Jelen def1de
+	int r, ok;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if ((m = sshbuf_new()) == NULL)
Jakub Jelen def1de
+		fatal("%s: sshbuf_new failed", __func__);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if ((r = sshbuf_put_cstring(m,
Jakub Jelen def1de
+	    store->filename ? store->filename : "")) != 0 ||
Jakub Jelen def1de
+	    (r = sshbuf_put_cstring(m,
Jakub Jelen def1de
+	    store->envvar ? store->envvar : "")) != 0 ||
Jakub Jelen def1de
+	    (r = sshbuf_put_cstring(m,
Jakub Jelen def1de
+	    store->envval ? store->envval : "")) != 0)
Jakub Jelen def1de
+		fatal("%s: buffer error: %s", __func__, ssh_err(r));
Jakub Jelen def1de
+
Jakub Jelen def1de
+	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSUPCREDS, m);
Jakub Jelen def1de
+	mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSUPCREDS, m);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if ((r = sshbuf_get_u32(m, &ok)) != 0)
Jakub Jelen def1de
+		fatal("%s: buffer error: %s", __func__, ssh_err(r));
Jakub Jelen def1de
+
Jakub Jelen def1de
+	sshbuf_free(m);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	return (ok);
Jakub Jelen def1de
+}
Jakub Jelen def1de
+
Jakub Jelen def1de
 #endif /* GSSAPI */
Jakub Jelen def1de
diff --git a/monitor_wrap.h b/monitor_wrap.h
Jakub Jelen 51f5c1
index 23ab096a..485590c1 100644
Jakub Jelen def1de
--- a/monitor_wrap.h
Jakub Jelen def1de
+++ b/monitor_wrap.h
Jakub Jelen 51f5c1
@@ -64,8 +64,10 @@ int mm_sshkey_verify(const struct sshkey *, const u_char *, size_t,
Jakub Jelen def1de
 OM_uint32 mm_ssh_gssapi_server_ctx(Gssctxt **, gss_OID);
Jakub Jelen def1de
 OM_uint32 mm_ssh_gssapi_accept_ctx(Gssctxt *,
Jakub Jelen def1de
    gss_buffer_desc *, gss_buffer_desc *, OM_uint32 *);
Jakub Jelen def1de
-int mm_ssh_gssapi_userok(char *user);
Jakub Jelen def1de
+int mm_ssh_gssapi_userok(char *user, struct passwd *, int kex);
Jakub Jelen def1de
 OM_uint32 mm_ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t);
Jakub Jelen def1de
+OM_uint32 mm_ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t);
Jakub Jelen def1de
+int mm_ssh_gssapi_update_creds(ssh_gssapi_ccache *);
Jakub Jelen def1de
 #endif
Jakub Jelen def1de
 
Jakub Jelen def1de
 #ifdef USE_PAM
Jakub Jelen def1de
diff --git a/readconf.c b/readconf.c
Jakub Jelen 51f5c1
index f3cac6b3..da8022dd 100644
Jakub Jelen def1de
--- a/readconf.c
Jakub Jelen def1de
+++ b/readconf.c
Jakub Jelen def1de
@@ -67,6 +67,7 @@
Jakub Jelen def1de
 #include "uidswap.h"
Jakub Jelen def1de
 #include "myproposal.h"
Jakub Jelen def1de
 #include "digest.h"
Jakub Jelen def1de
+#include "ssh-gss.h"
Jakub Jelen def1de
 
Jakub Jelen def1de
 /* Format of the configuration file:
Jakub Jelen def1de
 
Jakub Jelen 51f5c1
@@ -160,6 +161,8 @@ typedef enum {
Jakub Jelen def1de
 	oClearAllForwardings, oNoHostAuthenticationForLocalhost,
Jakub Jelen def1de
 	oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
Jakub Jelen def1de
 	oAddressFamily, oGssAuthentication, oGssDelegateCreds,
Jakub Jelen def1de
+	oGssTrustDns, oGssKeyEx, oGssClientIdentity, oGssRenewalRekey,
Jakub Jelen def1de
+	oGssServerIdentity, oGssKexAlgorithms,
Jakub Jelen def1de
 	oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
Jakub Jelen def1de
 	oSendEnv, oSetEnv, oControlPath, oControlMaster, oControlPersist,
Jakub Jelen def1de
 	oHashKnownHosts,
Jakub Jelen 51f5c1
@@ -204,10 +207,22 @@ static struct {
Jakub Jelen def1de
 	/* Sometimes-unsupported options */
Jakub Jelen def1de
 #if defined(GSSAPI)
Jakub Jelen def1de
 	{ "gssapiauthentication", oGssAuthentication },
Jakub Jelen def1de
+	{ "gssapikeyexchange", oGssKeyEx },
Jakub Jelen def1de
 	{ "gssapidelegatecredentials", oGssDelegateCreds },
Jakub Jelen def1de
+	{ "gssapitrustdns", oGssTrustDns },
Jakub Jelen def1de
+	{ "gssapiclientidentity", oGssClientIdentity },
Jakub Jelen def1de
+	{ "gssapiserveridentity", oGssServerIdentity },
Jakub Jelen def1de
+	{ "gssapirenewalforcesrekey", oGssRenewalRekey },
Jakub Jelen def1de
+	{ "gssapikexalgorithms", oGssKexAlgorithms },
Jakub Jelen def1de
 # else
Jakub Jelen def1de
 	{ "gssapiauthentication", oUnsupported },
Jakub Jelen def1de
+	{ "gssapikeyexchange", oUnsupported },
Jakub Jelen def1de
 	{ "gssapidelegatecredentials", oUnsupported },
Jakub Jelen def1de
+	{ "gssapitrustdns", oUnsupported },
Jakub Jelen def1de
+	{ "gssapiclientidentity", oUnsupported },
Jakub Jelen def1de
+	{ "gssapiserveridentity", oUnsupported },
Jakub Jelen def1de
+	{ "gssapirenewalforcesrekey", oUnsupported },
Jakub Jelen def1de
+	{ "gssapikexalgorithms", oUnsupported },
Jakub Jelen def1de
 #endif
Jakub Jelen def1de
 #ifdef ENABLE_PKCS11
Jakub Jelen def1de
 	{ "pkcs11provider", oPKCS11Provider },
Jakub Jelen 51f5c1
@@ -1029,10 +1044,42 @@ parse_time:
Jakub Jelen def1de
 		intptr = &options->gss_authentication;
Jakub Jelen def1de
 		goto parse_flag;
Jakub Jelen def1de
 
Jakub Jelen def1de
+	case oGssKeyEx:
Jakub Jelen def1de
+		intptr = &options->gss_keyex;
Jakub Jelen def1de
+		goto parse_flag;
Jakub Jelen def1de
+
Jakub Jelen def1de
 	case oGssDelegateCreds:
Jakub Jelen def1de
 		intptr = &options->gss_deleg_creds;
Jakub Jelen def1de
 		goto parse_flag;
Jakub Jelen def1de
 
Jakub Jelen def1de
+	case oGssTrustDns:
Jakub Jelen def1de
+		intptr = &options->gss_trust_dns;
Jakub Jelen def1de
+		goto parse_flag;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	case oGssClientIdentity:
Jakub Jelen def1de
+		charptr = &options->gss_client_identity;
Jakub Jelen def1de
+		goto parse_string;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	case oGssServerIdentity:
Jakub Jelen def1de
+		charptr = &options->gss_server_identity;
Jakub Jelen def1de
+		goto parse_string;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	case oGssRenewalRekey:
Jakub Jelen def1de
+		intptr = &options->gss_renewal_rekey;
Jakub Jelen def1de
+		goto parse_flag;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	case oGssKexAlgorithms:
Jakub Jelen def1de
+		arg = strdelim(&s);
Jakub Jelen def1de
+		if (!arg || *arg == '\0')
Jakub Jelen def1de
+			fatal("%.200s line %d: Missing argument.",
Jakub Jelen def1de
+			    filename, linenum);
Jakub Jelen def1de
+		if (!kex_gss_names_valid(arg))
Jakub Jelen def1de
+			fatal("%.200s line %d: Bad GSSAPI KexAlgorithms '%s'.",
Jakub Jelen def1de
+			    filename, linenum, arg ? arg : "<NONE>");
Jakub Jelen def1de
+		if (*activep && options->gss_kex_algorithms == NULL)
Jakub Jelen def1de
+			options->gss_kex_algorithms = xstrdup(arg);
Jakub Jelen def1de
+		break;
Jakub Jelen def1de
+
Jakub Jelen def1de
 	case oBatchMode:
Jakub Jelen def1de
 		intptr = &options->batch_mode;
Jakub Jelen def1de
 		goto parse_flag;
Jakub Jelen 51f5c1
@@ -1911,7 +1958,13 @@ initialize_options(Options * options)
Jakub Jelen def1de
 	options->pubkey_authentication = -1;
Jakub Jelen def1de
 	options->challenge_response_authentication = -1;
Jakub Jelen def1de
 	options->gss_authentication = -1;
Jakub Jelen def1de
+	options->gss_keyex = -1;
Jakub Jelen def1de
 	options->gss_deleg_creds = -1;
Jakub Jelen def1de
+	options->gss_trust_dns = -1;
Jakub Jelen def1de
+	options->gss_renewal_rekey = -1;
Jakub Jelen def1de
+	options->gss_client_identity = NULL;
Jakub Jelen def1de
+	options->gss_server_identity = NULL;
Jakub Jelen def1de
+	options->gss_kex_algorithms = NULL;
Jakub Jelen def1de
 	options->password_authentication = -1;
Jakub Jelen def1de
 	options->kbd_interactive_authentication = -1;
Jakub Jelen def1de
 	options->kbd_interactive_devices = NULL;
Jakub Jelen 51f5c1
@@ -2059,8 +2112,18 @@ fill_default_options(Options * options)
Jakub Jelen def1de
 		options->challenge_response_authentication = 1;
Jakub Jelen def1de
 	if (options->gss_authentication == -1)
Jakub Jelen def1de
 		options->gss_authentication = 0;
Jakub Jelen def1de
+	if (options->gss_keyex == -1)
Jakub Jelen def1de
+		options->gss_keyex = 0;
Jakub Jelen def1de
 	if (options->gss_deleg_creds == -1)
Jakub Jelen def1de
 		options->gss_deleg_creds = 0;
Jakub Jelen def1de
+	if (options->gss_trust_dns == -1)
Jakub Jelen def1de
+		options->gss_trust_dns = 0;
Jakub Jelen def1de
+	if (options->gss_renewal_rekey == -1)
Jakub Jelen def1de
+		options->gss_renewal_rekey = 0;
Jakub Jelen def1de
+#ifdef GSSAPI
Jakub Jelen def1de
+	if (options->gss_kex_algorithms == NULL)
Jakub Jelen def1de
+		options->gss_kex_algorithms = strdup(GSS_KEX_DEFAULT_KEX);
Jakub Jelen def1de
+#endif
Jakub Jelen def1de
 	if (options->password_authentication == -1)
Jakub Jelen def1de
 		options->password_authentication = 1;
Jakub Jelen def1de
 	if (options->kbd_interactive_authentication == -1)
Jakub Jelen 51f5c1
@@ -2702,7 +2765,14 @@ dump_client_config(Options *o, const char *host)
Jakub Jelen def1de
 	dump_cfg_fmtint(oGatewayPorts, o->fwd_opts.gateway_ports);
Jakub Jelen def1de
 #ifdef GSSAPI
Jakub Jelen def1de
 	dump_cfg_fmtint(oGssAuthentication, o->gss_authentication);
Jakub Jelen def1de
+	dump_cfg_fmtint(oGssKeyEx, o->gss_keyex);
Jakub Jelen def1de
 	dump_cfg_fmtint(oGssDelegateCreds, o->gss_deleg_creds);
Jakub Jelen def1de
+	dump_cfg_fmtint(oGssTrustDns, o->gss_trust_dns);
Jakub Jelen def1de
+	dump_cfg_fmtint(oGssRenewalRekey, o->gss_renewal_rekey);
Jakub Jelen def1de
+	dump_cfg_string(oGssClientIdentity, o->gss_client_identity);
Jakub Jelen def1de
+	dump_cfg_string(oGssServerIdentity, o->gss_server_identity);
Jakub Jelen def1de
+	dump_cfg_string(oGssKexAlgorithms, o->gss_kex_algorithms ?
Jakub Jelen def1de
+	    o->gss_kex_algorithms : GSS_KEX_DEFAULT_KEX);
Jakub Jelen def1de
 #endif /* GSSAPI */
Jakub Jelen def1de
 	dump_cfg_fmtint(oHashKnownHosts, o->hash_known_hosts);
Jakub Jelen def1de
 	dump_cfg_fmtint(oHostbasedAuthentication, o->hostbased_authentication);
Jakub Jelen def1de
diff --git a/readconf.h b/readconf.h
Jakub Jelen 51f5c1
index feedb3d2..a8a8870d 100644
Jakub Jelen def1de
--- a/readconf.h
Jakub Jelen def1de
+++ b/readconf.h
Jakub Jelen 51f5c1
@@ -41,7 +41,13 @@ typedef struct {
Jakub Jelen def1de
 	int     challenge_response_authentication;
Jakub Jelen def1de
 					/* Try S/Key or TIS, authentication. */
Jakub Jelen def1de
 	int     gss_authentication;	/* Try GSS authentication */
Jakub Jelen def1de
+	int     gss_keyex;		/* Try GSS key exchange */
Jakub Jelen def1de
 	int     gss_deleg_creds;	/* Delegate GSS credentials */
Jakub Jelen def1de
+	int	gss_trust_dns;		/* Trust DNS for GSS canonicalization */
Jakub Jelen def1de
+	int	gss_renewal_rekey;	/* Credential renewal forces rekey */
Jakub Jelen def1de
+	char    *gss_client_identity;   /* Principal to initiate GSSAPI with */
Jakub Jelen def1de
+	char    *gss_server_identity;   /* GSSAPI target principal */
Jakub Jelen def1de
+	char    *gss_kex_algorithms;	/* GSSAPI kex methods to be offered by client. */
Jakub Jelen def1de
 	int     password_authentication;	/* Try password
Jakub Jelen def1de
 						 * authentication. */
Jakub Jelen def1de
 	int     kbd_interactive_authentication; /* Try keyboard-interactive auth. */
Jakub Jelen def1de
diff --git a/servconf.c b/servconf.c
Jakub Jelen 51f5c1
index 70f5f73f..191575a1 100644
Jakub Jelen def1de
--- a/servconf.c
Jakub Jelen def1de
+++ b/servconf.c
Jakub Jelen 51f5c1
@@ -69,6 +69,7 @@
Jakub Jelen def1de
 #include "auth.h"
Jakub Jelen def1de
 #include "myproposal.h"
Jakub Jelen def1de
 #include "digest.h"
Jakub Jelen def1de
+#include "ssh-gss.h"
Jakub Jelen def1de
 
Jakub Jelen def1de
 static void add_listen_addr(ServerOptions *, const char *,
Jakub Jelen def1de
     const char *, int);
Jakub Jelen 51f5c1
@@ -133,8 +134,11 @@ initialize_server_options(ServerOptions *options)
Jakub Jelen def1de
 	options->kerberos_ticket_cleanup = -1;
Jakub Jelen def1de
 	options->kerberos_get_afs_token = -1;
Jakub Jelen def1de
 	options->gss_authentication=-1;
Jakub Jelen def1de
+	options->gss_keyex = -1;
Jakub Jelen def1de
 	options->gss_cleanup_creds = -1;
Jakub Jelen def1de
 	options->gss_strict_acceptor = -1;
Jakub Jelen def1de
+	options->gss_store_rekey = -1;
Jakub Jelen def1de
+	options->gss_kex_algorithms = NULL;
Jakub Jelen def1de
 	options->password_authentication = -1;
Jakub Jelen def1de
 	options->kbd_interactive_authentication = -1;
Jakub Jelen def1de
 	options->challenge_response_authentication = -1;
Jakub Jelen 51f5c1
@@ -375,10 +379,18 @@ fill_default_server_options(ServerOptions *options)
Jakub Jelen def1de
 		options->kerberos_get_afs_token = 0;
Jakub Jelen def1de
 	if (options->gss_authentication == -1)
Jakub Jelen def1de
 		options->gss_authentication = 0;
Jakub Jelen def1de
+	if (options->gss_keyex == -1)
Jakub Jelen def1de
+		options->gss_keyex = 0;
Jakub Jelen def1de
 	if (options->gss_cleanup_creds == -1)
Jakub Jelen def1de
 		options->gss_cleanup_creds = 1;
Jakub Jelen def1de
 	if (options->gss_strict_acceptor == -1)
Jakub Jelen def1de
 		options->gss_strict_acceptor = 1;
Jakub Jelen def1de
+	if (options->gss_store_rekey == -1)
Jakub Jelen def1de
+		options->gss_store_rekey = 0;
Jakub Jelen def1de
+#ifdef GSSAPI
Jakub Jelen def1de
+	if (options->gss_kex_algorithms == NULL)
Jakub Jelen def1de
+		options->gss_kex_algorithms = strdup(GSS_KEX_DEFAULT_KEX);
Jakub Jelen def1de
+#endif
Jakub Jelen def1de
 	if (options->password_authentication == -1)
Jakub Jelen def1de
 		options->password_authentication = 1;
Jakub Jelen def1de
 	if (options->kbd_interactive_authentication == -1)
Jakub Jelen 51f5c1
@@ -531,6 +543,7 @@ typedef enum {
Jakub Jelen def1de
 	sHostKeyAlgorithms,
Jakub Jelen def1de
 	sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile,
Jakub Jelen def1de
 	sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor,
Jakub Jelen def1de
+	sGssKeyEx, sGssKexAlgorithms, sGssStoreRekey,
Jakub Jelen def1de
 	sAcceptEnv, sSetEnv, sPermitTunnel,
Jakub Jelen def1de
 	sMatch, sPermitOpen, sPermitListen, sForceCommand, sChrootDirectory,
Jakub Jelen def1de
 	sUsePrivilegeSeparation, sAllowAgentForwarding,
Jakub Jelen 51f5c1
@@ -607,12 +620,22 @@ static struct {
Jakub Jelen def1de
 #ifdef GSSAPI
Jakub Jelen def1de
 	{ "gssapiauthentication", sGssAuthentication, SSHCFG_ALL },
Jakub Jelen def1de
 	{ "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL },
Jakub Jelen def1de
+	{ "gssapicleanupcreds", sGssCleanupCreds, SSHCFG_GLOBAL },
Jakub Jelen def1de
 	{ "gssapistrictacceptorcheck", sGssStrictAcceptor, SSHCFG_GLOBAL },
Jakub Jelen def1de
+	{ "gssapikeyexchange", sGssKeyEx, SSHCFG_GLOBAL },
Jakub Jelen def1de
+	{ "gssapistorecredentialsonrekey", sGssStoreRekey, SSHCFG_GLOBAL },
Jakub Jelen def1de
+	{ "gssapikexalgorithms", sGssKexAlgorithms, SSHCFG_GLOBAL },
Jakub Jelen def1de
 #else
Jakub Jelen def1de
 	{ "gssapiauthentication", sUnsupported, SSHCFG_ALL },
Jakub Jelen def1de
 	{ "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL },
Jakub Jelen def1de
+	{ "gssapicleanupcreds", sUnsupported, SSHCFG_GLOBAL },
Jakub Jelen def1de
 	{ "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL },
Jakub Jelen def1de
+	{ "gssapikeyexchange", sUnsupported, SSHCFG_GLOBAL },
Jakub Jelen def1de
+	{ "gssapistorecredentialsonrekey", sUnsupported, SSHCFG_GLOBAL },
Jakub Jelen def1de
+	{ "gssapikexalgorithms", sUnsupported, SSHCFG_GLOBAL },
Jakub Jelen def1de
 #endif
Jakub Jelen def1de
+	{ "gssusesessionccache", sUnsupported, SSHCFG_GLOBAL },
Jakub Jelen def1de
+	{ "gssapiusesessioncredcache", sUnsupported, SSHCFG_GLOBAL },
Jakub Jelen def1de
 	{ "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL },
Jakub Jelen def1de
 	{ "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL },
Jakub Jelen def1de
 	{ "challengeresponseauthentication", sChallengeResponseAuthentication, SSHCFG_GLOBAL },
Jakub Jelen 51f5c1
@@ -1548,6 +1571,10 @@ process_server_config_line_depth(ServerOptions *options, char *line,
Jakub Jelen def1de
 		intptr = &options->gss_authentication;
Jakub Jelen def1de
 		goto parse_flag;
Jakub Jelen def1de
 
Jakub Jelen def1de
+	case sGssKeyEx:
Jakub Jelen def1de
+		intptr = &options->gss_keyex;
Jakub Jelen def1de
+		goto parse_flag;
Jakub Jelen def1de
+
Jakub Jelen def1de
 	case sGssCleanupCreds:
Jakub Jelen def1de
 		intptr = &options->gss_cleanup_creds;
Jakub Jelen def1de
 		goto parse_flag;
Jakub Jelen 51f5c1
@@ -1556,6 +1583,22 @@ process_server_config_line_depth(ServerOptions *options, char *line,
Jakub Jelen def1de
 		intptr = &options->gss_strict_acceptor;
Jakub Jelen def1de
 		goto parse_flag;
Jakub Jelen def1de
 
Jakub Jelen def1de
+	case sGssStoreRekey:
Jakub Jelen def1de
+		intptr = &options->gss_store_rekey;
Jakub Jelen def1de
+		goto parse_flag;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	case sGssKexAlgorithms:
Jakub Jelen def1de
+		arg = strdelim(&cp;;
Jakub Jelen def1de
+		if (!arg || *arg == '\0')
Jakub Jelen def1de
+			fatal("%.200s line %d: Missing argument.",
Jakub Jelen def1de
+			    filename, linenum);
Jakub Jelen def1de
+		if (!kex_gss_names_valid(arg))
Jakub Jelen def1de
+			fatal("%.200s line %d: Bad GSSAPI KexAlgorithms '%s'.",
Jakub Jelen def1de
+			    filename, linenum, arg ? arg : "<NONE>");
Jakub Jelen def1de
+		if (*activep && options->gss_kex_algorithms == NULL)
Jakub Jelen def1de
+			options->gss_kex_algorithms = xstrdup(arg);
Jakub Jelen def1de
+		break;
Jakub Jelen def1de
+
Jakub Jelen def1de
 	case sPasswordAuthentication:
Jakub Jelen def1de
 		intptr = &options->password_authentication;
Jakub Jelen def1de
 		goto parse_flag;
Jakub Jelen 51f5c1
@@ -2777,6 +2820,10 @@ dump_config(ServerOptions *o)
Jakub Jelen def1de
 #ifdef GSSAPI
Jakub Jelen def1de
 	dump_cfg_fmtint(sGssAuthentication, o->gss_authentication);
Jakub Jelen def1de
 	dump_cfg_fmtint(sGssCleanupCreds, o->gss_cleanup_creds);
Jakub Jelen def1de
+	dump_cfg_fmtint(sGssKeyEx, o->gss_keyex);
Jakub Jelen def1de
+	dump_cfg_fmtint(sGssStrictAcceptor, o->gss_strict_acceptor);
Jakub Jelen def1de
+	dump_cfg_fmtint(sGssStoreRekey, o->gss_store_rekey);
Jakub Jelen def1de
+	dump_cfg_string(sGssKexAlgorithms, o->gss_kex_algorithms);
Jakub Jelen def1de
 #endif
Jakub Jelen def1de
 	dump_cfg_fmtint(sPasswordAuthentication, o->password_authentication);
Jakub Jelen def1de
 	dump_cfg_fmtint(sKbdInteractiveAuthentication,
Jakub Jelen def1de
diff --git a/servconf.h b/servconf.h
Jakub Jelen 51f5c1
index 4202a2d0..3f47ea25 100644
Jakub Jelen def1de
--- a/servconf.h
Jakub Jelen def1de
+++ b/servconf.h
Jakub Jelen 51f5c1
@@ -132,8 +132,11 @@ typedef struct {
Jakub Jelen def1de
 	int     kerberos_get_afs_token;		/* If true, try to get AFS token if
Jakub Jelen def1de
 						 * authenticated with Kerberos. */
Jakub Jelen def1de
 	int     gss_authentication;	/* If true, permit GSSAPI authentication */
Jakub Jelen def1de
+	int     gss_keyex;		/* If true, permit GSSAPI key exchange */
Jakub Jelen def1de
 	int     gss_cleanup_creds;	/* If true, destroy cred cache on logout */
Jakub Jelen def1de
 	int     gss_strict_acceptor;	/* If true, restrict the GSSAPI acceptor name */
Jakub Jelen def1de
+	int 	gss_store_rekey;
Jakub Jelen def1de
+	char   *gss_kex_algorithms;	/* GSSAPI kex methods to be offered by client. */
Jakub Jelen def1de
 	int     password_authentication;	/* If true, permit password
Jakub Jelen def1de
 						 * authentication. */
Jakub Jelen def1de
 	int     kbd_interactive_authentication;	/* If true, permit */
Jakub Jelen def1de
diff --git a/session.c b/session.c
Jakub Jelen 51f5c1
index 8c0e54f7..06a33442 100644
Jakub Jelen def1de
--- a/session.c
Jakub Jelen def1de
+++ b/session.c
Jakub Jelen 51f5c1
@@ -2678,13 +2678,19 @@ do_cleanup(struct ssh *ssh, Authctxt *authctxt)
Jakub Jelen def1de
 
Jakub Jelen def1de
 #ifdef KRB5
Jakub Jelen def1de
 	if (options.kerberos_ticket_cleanup &&
Jakub Jelen def1de
-	    authctxt->krb5_ctx)
Jakub Jelen def1de
+	    authctxt->krb5_ctx) {
Jakub Jelen def1de
+		temporarily_use_uid(authctxt->pw);
Jakub Jelen def1de
 		krb5_cleanup_proc(authctxt);
Jakub Jelen def1de
+		restore_uid();
Jakub Jelen def1de
+	}
Jakub Jelen def1de
 #endif
Jakub Jelen def1de
 
Jakub Jelen def1de
 #ifdef GSSAPI
Jakub Jelen def1de
-	if (options.gss_cleanup_creds)
Jakub Jelen def1de
+	if (options.gss_cleanup_creds) {
Jakub Jelen def1de
+		temporarily_use_uid(authctxt->pw);
Jakub Jelen def1de
 		ssh_gssapi_cleanup_creds();
Jakub Jelen def1de
+		restore_uid();
Jakub Jelen def1de
+	}
Jakub Jelen def1de
 #endif
Jakub Jelen def1de
 
Jakub Jelen def1de
 	/* remove agent socket */
Jakub Jelen def1de
diff --git a/ssh-gss.h b/ssh-gss.h
Jakub Jelen def1de
index 36180d07..70dd3665 100644
Jakub Jelen def1de
--- a/ssh-gss.h
Jakub Jelen def1de
+++ b/ssh-gss.h
Jakub Jelen def1de
@@ -1,6 +1,6 @@
Jakub Jelen def1de
 /* $OpenBSD: ssh-gss.h,v 1.14 2018/07/10 09:13:30 djm Exp $ */
Jakub Jelen def1de
 /*
Jakub Jelen def1de
- * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
Jakub Jelen def1de
+ * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved.
Jakub Jelen def1de
  *
Jakub Jelen def1de
  * Redistribution and use in source and binary forms, with or without
Jakub Jelen def1de
  * modification, are permitted provided that the following conditions
Jakub Jelen 1cc7c8
@@ -61,10 +61,34 @@
Jakub Jelen def1de
 
Jakub Jelen def1de
 #define SSH_GSS_OIDTYPE 0x06
Jakub Jelen def1de
 
Jakub Jelen def1de
+#define SSH2_MSG_KEXGSS_INIT                            30
Jakub Jelen def1de
+#define SSH2_MSG_KEXGSS_CONTINUE                        31
Jakub Jelen def1de
+#define SSH2_MSG_KEXGSS_COMPLETE                        32
Jakub Jelen def1de
+#define SSH2_MSG_KEXGSS_HOSTKEY                         33
Jakub Jelen def1de
+#define SSH2_MSG_KEXGSS_ERROR                           34
Jakub Jelen def1de
+#define SSH2_MSG_KEXGSS_GROUPREQ			40
Jakub Jelen def1de
+#define SSH2_MSG_KEXGSS_GROUP				41
Jakub Jelen def1de
+#define KEX_GSS_GRP1_SHA1_ID				"gss-group1-sha1-"
Jakub Jelen def1de
+#define KEX_GSS_GRP14_SHA1_ID				"gss-group14-sha1-"
Jakub Jelen def1de
+#define KEX_GSS_GRP14_SHA256_ID			"gss-group14-sha256-"
Jakub Jelen def1de
+#define KEX_GSS_GRP16_SHA512_ID			"gss-group16-sha512-"
Jakub Jelen def1de
+#define KEX_GSS_GEX_SHA1_ID				"gss-gex-sha1-"
Jakub Jelen def1de
+#define KEX_GSS_NISTP256_SHA256_ID			"gss-nistp256-sha256-"
Jakub Jelen def1de
+#define KEX_GSS_C25519_SHA256_ID			"gss-curve25519-sha256-"
Jakub Jelen def1de
+
Jakub Jelen def1de
+#define        GSS_KEX_DEFAULT_KEX \
Jakub Jelen 1cc7c8
+	KEX_GSS_GRP14_SHA256_ID "," \
Jakub Jelen 1cc7c8
+	KEX_GSS_GRP16_SHA512_ID	"," \
Jakub Jelen 1cc7c8
+	KEX_GSS_NISTP256_SHA256_ID "," \
Jakub Jelen 1cc7c8
+	KEX_GSS_C25519_SHA256_ID "," \
Jakub Jelen 169fdb
+	KEX_GSS_GRP14_SHA1_ID "," \
Jakub Jelen 169fdb
+	KEX_GSS_GEX_SHA1_ID
Jakub Jelen def1de
+
Jakub Jelen def1de
 typedef struct {
Jakub Jelen def1de
 	char *filename;
Jakub Jelen def1de
 	char *envvar;
Jakub Jelen def1de
 	char *envval;
Jakub Jelen def1de
+	struct passwd *owner;
Jakub Jelen def1de
 	void *data;
Jakub Jelen def1de
 } ssh_gssapi_ccache;
Jakub Jelen def1de
 
Jakub Jelen def1de
@@ -72,8 +92,11 @@ typedef struct {
Jakub Jelen def1de
 	gss_buffer_desc displayname;
Jakub Jelen def1de
 	gss_buffer_desc exportedname;
Jakub Jelen def1de
 	gss_cred_id_t creds;
Jakub Jelen def1de
+	gss_name_t name;
Jakub Jelen def1de
 	struct ssh_gssapi_mech_struct *mech;
Jakub Jelen def1de
 	ssh_gssapi_ccache store;
Jakub Jelen def1de
+	int used;
Jakub Jelen def1de
+	int updated;
Jakub Jelen def1de
 } ssh_gssapi_client;
Jakub Jelen def1de
 
Jakub Jelen def1de
 typedef struct ssh_gssapi_mech_struct {
Jakub Jelen def1de
@@ -84,6 +107,7 @@ typedef struct ssh_gssapi_mech_struct {
Jakub Jelen def1de
 	int (*userok) (ssh_gssapi_client *, char *);
Jakub Jelen def1de
 	int (*localname) (ssh_gssapi_client *, char **);
Jakub Jelen def1de
 	void (*storecreds) (ssh_gssapi_client *);
Jakub Jelen def1de
+	int (*updatecreds) (ssh_gssapi_ccache *, ssh_gssapi_client *);
Jakub Jelen def1de
 } ssh_gssapi_mech;
Jakub Jelen def1de
 
Jakub Jelen def1de
 typedef struct {
Jakub Jelen def1de
@@ -94,10 +118,11 @@ typedef struct {
Jakub Jelen def1de
 	gss_OID		oid; /* client */
Jakub Jelen def1de
 	gss_cred_id_t	creds; /* server */
Jakub Jelen def1de
 	gss_name_t	client; /* server */
Jakub Jelen def1de
-	gss_cred_id_t	client_creds; /* server */
Jakub Jelen def1de
+	gss_cred_id_t	client_creds; /* both */
Jakub Jelen def1de
 } Gssctxt;
Jakub Jelen def1de
 
Jakub Jelen def1de
 extern ssh_gssapi_mech *supported_mechs[];
Jakub Jelen def1de
+extern Gssctxt *gss_kex_context;
Jakub Jelen def1de
 
Jakub Jelen def1de
 int  ssh_gssapi_check_oid(Gssctxt *, void *, size_t);
Jakub Jelen def1de
 void ssh_gssapi_set_oid_data(Gssctxt *, void *, size_t);
Jakub Jelen def1de
@@ -109,6 +134,7 @@ OM_uint32 ssh_gssapi_test_oid_supported(OM_uint32 *, gss_OID, int *);
Jakub Jelen def1de
 
Jakub Jelen def1de
 struct sshbuf;
Jakub Jelen def1de
 int ssh_gssapi_get_buffer_desc(struct sshbuf *, gss_buffer_desc *);
Jakub Jelen def1de
+int ssh_gssapi_sshpkt_get_buffer_desc(struct ssh *, gss_buffer_desc *);
Jakub Jelen def1de
 
Jakub Jelen def1de
 OM_uint32 ssh_gssapi_import_name(Gssctxt *, const char *);
Jakub Jelen def1de
 OM_uint32 ssh_gssapi_init_ctx(Gssctxt *, int,
Jakub Jelen def1de
@@ -123,17 +149,33 @@ void ssh_gssapi_delete_ctx(Gssctxt **);
Jakub Jelen def1de
 OM_uint32 ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t);
Jakub Jelen def1de
 void ssh_gssapi_buildmic(struct sshbuf *, const char *,
Jakub Jelen def1de
     const char *, const char *);
Jakub Jelen def1de
-int ssh_gssapi_check_mechanism(Gssctxt **, gss_OID, const char *);
Jakub Jelen def1de
+int ssh_gssapi_check_mechanism(Gssctxt **, gss_OID, const char *, const char *);
Jakub Jelen def1de
+OM_uint32 ssh_gssapi_client_identity(Gssctxt *, const char *);
Jakub Jelen def1de
+int ssh_gssapi_credentials_updated(Gssctxt *);
Jakub Jelen def1de
 
Jakub Jelen def1de
 /* In the server */
Jakub Jelen def1de
+typedef int ssh_gssapi_check_fn(Gssctxt **, gss_OID, const char *,
Jakub Jelen def1de
+    const char *);
Jakub Jelen def1de
+char *ssh_gssapi_client_mechanisms(const char *, const char *, const char *);
Jakub Jelen def1de
+char *ssh_gssapi_kex_mechs(gss_OID_set, ssh_gssapi_check_fn *, const char *,
Jakub Jelen def1de
+    const char *, const char *);
Jakub Jelen def1de
+gss_OID ssh_gssapi_id_kex(Gssctxt *, char *, int);
Jakub Jelen def1de
+int ssh_gssapi_server_check_mech(Gssctxt **,gss_OID, const char *,
Jakub Jelen def1de
+    const char *);
Jakub Jelen def1de
 OM_uint32 ssh_gssapi_server_ctx(Gssctxt **, gss_OID);
Jakub Jelen def1de
-int ssh_gssapi_userok(char *name);
Jakub Jelen def1de
+int ssh_gssapi_userok(char *name, struct passwd *, int kex);
Jakub Jelen def1de
 OM_uint32 ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t);
Jakub Jelen def1de
 void ssh_gssapi_do_child(char ***, u_int *);
Jakub Jelen def1de
 void ssh_gssapi_cleanup_creds(void);
Jakub Jelen def1de
 void ssh_gssapi_storecreds(void);
Jakub Jelen def1de
 const char *ssh_gssapi_displayname(void);
Jakub Jelen def1de
 
Jakub Jelen def1de
+char *ssh_gssapi_server_mechanisms(void);
Jakub Jelen def1de
+int ssh_gssapi_oid_table_ok(void);
Jakub Jelen def1de
+
Jakub Jelen def1de
+int ssh_gssapi_update_creds(ssh_gssapi_ccache *store);
Jakub Jelen def1de
+void ssh_gssapi_rekey_creds(void);
Jakub Jelen def1de
+
Jakub Jelen def1de
 #endif /* GSSAPI */
Jakub Jelen def1de
 
Jakub Jelen def1de
 #endif /* _SSH_GSS_H */
Jakub Jelen def1de
diff --git a/ssh.1 b/ssh.1
Jakub Jelen 51f5c1
index 60de6087..db5c65bc 100644
Jakub Jelen def1de
--- a/ssh.1
Jakub Jelen def1de
+++ b/ssh.1
Jakub Jelen 51f5c1
@@ -503,7 +503,13 @@ For full details of the options listed below, and their possible values, see
Jakub Jelen def1de
 .It GatewayPorts
Jakub Jelen def1de
 .It GlobalKnownHostsFile
Jakub Jelen def1de
 .It GSSAPIAuthentication
Jakub Jelen def1de
+.It GSSAPIKeyExchange
Jakub Jelen def1de
+.It GSSAPIClientIdentity
Jakub Jelen def1de
 .It GSSAPIDelegateCredentials
Jakub Jelen def1de
+.It GSSAPIKexAlgorithms
Jakub Jelen def1de
+.It GSSAPIRenewalForcesRekey
Jakub Jelen def1de
+.It GSSAPIServerIdentity
Jakub Jelen def1de
+.It GSSAPITrustDns
Jakub Jelen def1de
 .It HashKnownHosts
Jakub Jelen def1de
 .It Host
Jakub Jelen def1de
 .It HostbasedAuthentication
Jakub Jelen 51f5c1
@@ -579,6 +585,8 @@ flag),
Jakub Jelen def1de
 (supported message integrity codes),
Jakub Jelen def1de
 .Ar kex
Jakub Jelen def1de
 (key exchange algorithms),
Jakub Jelen def1de
+.Ar kex-gss
Jakub Jelen def1de
+(GSSAPI key exchange algorithms),
Jakub Jelen def1de
 .Ar key
Jakub Jelen def1de
 (key types),
Jakub Jelen def1de
 .Ar key-cert
Jakub Jelen def1de
diff --git a/ssh.c b/ssh.c
Jakub Jelen 51f5c1
index 15aee569..110cf9c1 100644
Jakub Jelen def1de
--- a/ssh.c
Jakub Jelen def1de
+++ b/ssh.c
Jakub Jelen 51f5c1
@@ -747,6 +747,8 @@ main(int ac, char **av)
Jakub Jelen 51f5c1
 			else if (strcmp(optarg, "kex") == 0 ||
Jakub Jelen 51f5c1
 			    strcasecmp(optarg, "KexAlgorithms") == 0)
Jakub Jelen def1de
 				cp = kex_alg_list('\n');
Jakub Jelen def1de
+			else if (strcmp(optarg, "kex-gss") == 0)
Jakub Jelen def1de
+				cp = kex_gss_alg_list('\n');
Jakub Jelen def1de
 			else if (strcmp(optarg, "key") == 0)
Jakub Jelen def1de
 				cp = sshkey_alg_list(0, 0, 0, '\n');
Jakub Jelen def1de
 			else if (strcmp(optarg, "key-cert") == 0)
Jakub Jelen 51f5c1
@@ -772,8 +774,8 @@ main(int ac, char **av)
Jakub Jelen 51f5c1
 			} else if (strcmp(optarg, "help") == 0) {
Jakub Jelen def1de
 				cp = xstrdup(
Jakub Jelen 51f5c1
 				    "cipher\ncipher-auth\ncompression\nkex\n"
Jakub Jelen 51f5c1
-				    "key\nkey-cert\nkey-plain\nkey-sig\nmac\n"
Jakub Jelen 51f5c1
-				    "protocol-version\nsig");
Jakub Jelen 51f5c1
+				    "kex-gss\nkey\nkey-cert\nkey-plain\n"
Jakub Jelen 51f5c1
+				    "key-sig\nmac\nprotocol-version\nsig");
Jakub Jelen def1de
 			}
Jakub Jelen 51f5c1
 			if (cp == NULL)
Jakub Jelen 51f5c1
 				fatal("Unsupported query \"%s\"", optarg);
Jakub Jelen def1de
diff --git a/ssh_config b/ssh_config
Jakub Jelen def1de
index 5e8ef548..1ff999b6 100644
Jakub Jelen def1de
--- a/ssh_config
Jakub Jelen def1de
+++ b/ssh_config
Jakub Jelen def1de
@@ -24,6 +24,8 @@
Jakub Jelen def1de
 #   HostbasedAuthentication no
Jakub Jelen def1de
 #   GSSAPIAuthentication no
Jakub Jelen def1de
 #   GSSAPIDelegateCredentials no
Jakub Jelen def1de
+#   GSSAPIKeyExchange no
Jakub Jelen def1de
+#   GSSAPITrustDNS no
Jakub Jelen def1de
 #   BatchMode no
Jakub Jelen def1de
 #   CheckHostIP yes
Jakub Jelen def1de
 #   AddressFamily any
Jakub Jelen def1de
diff --git a/ssh_config.5 b/ssh_config.5
Jakub Jelen 51f5c1
index 06a32d31..3f490697 100644
Jakub Jelen def1de
--- a/ssh_config.5
Jakub Jelen def1de
+++ b/ssh_config.5
Jakub Jelen 1cc7c8
@@ -766,10 +766,68 @@ The default is
Jakub Jelen def1de
 Specifies whether user authentication based on GSSAPI is allowed.
Jakub Jelen def1de
 The default is
Jakub Jelen def1de
 .Cm no .
Jakub Jelen def1de
+.It Cm GSSAPIClientIdentity
Jakub Jelen def1de
+If set, specifies the GSSAPI client identity that ssh should use when
Jakub Jelen def1de
+connecting to the server. The default is unset, which means that the default
Jakub Jelen def1de
+identity will be used.
Jakub Jelen def1de
 .It Cm GSSAPIDelegateCredentials
Jakub Jelen def1de
 Forward (delegate) credentials to the server.
Jakub Jelen def1de
 The default is
Jakub Jelen def1de
 .Cm no .
Jakub Jelen def1de
+.It Cm GSSAPIKeyExchange
Jakub Jelen def1de
+Specifies whether key exchange based on GSSAPI may be used. When using
Jakub Jelen def1de
+GSSAPI key exchange the server need not have a host key.
Jakub Jelen def1de
+The default is
Jakub Jelen def1de
+.Dq no .
Jakub Jelen def1de
+.It Cm GSSAPIRenewalForcesRekey
Jakub Jelen def1de
+If set to
Jakub Jelen def1de
+.Dq yes
Jakub Jelen def1de
+then renewal of the client's GSSAPI credentials will force the rekeying of the
Jakub Jelen def1de
+ssh connection. With a compatible server, this will delegate the renewed
Jakub Jelen def1de
+credentials to a session on the server.
Jakub Jelen def1de
+.Pp
Jakub Jelen def1de
+Checks are made to ensure that credentials are only propagated when the new
Jakub Jelen def1de
+credentials match the old ones on the originating client and where the
Jakub Jelen def1de
+receiving server still has the old set in its cache.
Jakub Jelen def1de
+.Pp
Jakub Jelen def1de
+The default is
Jakub Jelen def1de
+.Dq no .
Jakub Jelen def1de
+.Pp
Jakub Jelen def1de
+For this to work
Jakub Jelen def1de
+.Cm GSSAPIKeyExchange
Jakub Jelen def1de
+needs to be enabled in the server and also used by the client.
Jakub Jelen def1de
+.It Cm GSSAPIServerIdentity
Jakub Jelen def1de
+If set, specifies the GSSAPI server identity that ssh should expect when
Jakub Jelen def1de
+connecting to the server. The default is unset, which means that the
Jakub Jelen def1de
+expected GSSAPI server identity will be determined from the target
Jakub Jelen def1de
+hostname.
Jakub Jelen def1de
+.It Cm GSSAPITrustDns
Jakub Jelen def1de
+Set to
Jakub Jelen def1de
+.Dq yes
Jakub Jelen def1de
+to indicate that the DNS is trusted to securely canonicalize
Jakub Jelen def1de
+the name of the host being connected to. If
Jakub Jelen def1de
+.Dq no ,
Jakub Jelen def1de
+the hostname entered on the
Jakub Jelen def1de
+command line will be passed untouched to the GSSAPI library.
Jakub Jelen def1de
+The default is
Jakub Jelen def1de
+.Dq no .
Jakub Jelen def1de
+.It Cm GSSAPIKexAlgorithms
Jakub Jelen def1de
+The list of key exchange algorithms that are offered for GSSAPI
Jakub Jelen def1de
+key exchange. Possible values are
Jakub Jelen def1de
+.Bd -literal -offset 3n
Jakub Jelen def1de
+gss-gex-sha1-,
Jakub Jelen def1de
+gss-group1-sha1-,
Jakub Jelen def1de
+gss-group14-sha1-,
Jakub Jelen def1de
+gss-group14-sha256-,
Jakub Jelen def1de
+gss-group16-sha512-,
Jakub Jelen def1de
+gss-nistp256-sha256-,
Jakub Jelen def1de
+gss-curve25519-sha256-
Jakub Jelen def1de
+.Ed
Jakub Jelen def1de
+.Pp
Jakub Jelen def1de
+The default is
Jakub Jelen 1cc7c8
+.Dq gss-group14-sha256-,gss-group16-sha512-,gss-nistp256-sha256-,
Jakub Jelen 1cc7c8
+gss-curve25519-sha256-,gss-group14-sha1-,gss-gex-sha1- .
Jakub Jelen 1cc7c8
+This option only applies to connections using GSSAPI.
Jakub Jelen def1de
 .It Cm HashKnownHosts
Jakub Jelen def1de
 Indicates that
Jakub Jelen def1de
 .Xr ssh 1
Jakub Jelen def1de
diff --git a/sshconnect2.c b/sshconnect2.c
Jakub Jelen 51f5c1
index af00fb30..03bc87eb 100644
Jakub Jelen def1de
--- a/sshconnect2.c
Jakub Jelen def1de
+++ b/sshconnect2.c
Jakub Jelen 51f5c1
@@ -80,8 +80,6 @@
Jakub Jelen def1de
 #endif
Jakub Jelen def1de
 
Jakub Jelen def1de
 /* import */
Jakub Jelen def1de
-extern char *client_version_string;
Jakub Jelen def1de
-extern char *server_version_string;
Jakub Jelen def1de
 extern Options options;
Jakub Jelen def1de
 
Jakub Jelen def1de
 /*
Jakub Jelen 51f5c1
@@ -163,6 +161,11 @@ ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port)
Jakub Jelen def1de
 	char *s, *all_key;
Jakub Jelen 51f5c1
 	int r, use_known_hosts_order = 0;
Jakub Jelen def1de
 
Jakub Jelen def1de
+#if defined(GSSAPI) && defined(WITH_OPENSSL)
Jakub Jelen def1de
+	char *orig = NULL, *gss = NULL;
Jakub Jelen def1de
+	char *gss_host = NULL;
Jakub Jelen def1de
+#endif
Jakub Jelen def1de
+
Jakub Jelen def1de
 	xxx_host = host;
Jakub Jelen def1de
 	xxx_hostaddr = hostaddr;
Jakub Jelen def1de
 
Jakub Jelen 57ba1b
@@ -206,6 +209,42 @@ ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port)
Jakub Jelen 51f5c1
 		    compat_pkalg_proposal(options.hostkeyalgorithms);
Jakub Jelen def1de
 	}
Jakub Jelen def1de
 
Jakub Jelen def1de
+#if defined(GSSAPI) && defined(WITH_OPENSSL)
Jakub Jelen def1de
+	if (options.gss_keyex) {
Jakub Jelen def1de
+		/* Add the GSSAPI mechanisms currently supported on this
Jakub Jelen def1de
+		 * client to the key exchange algorithm proposal */
Jakub Jelen def1de
+		orig = myproposal[PROPOSAL_KEX_ALGS];
Jakub Jelen def1de
+
Jakub Jelen 57ba1b
+		if (options.gss_server_identity) {
Jakub Jelen def1de
+			gss_host = xstrdup(options.gss_server_identity);
Jakub Jelen 57ba1b
+		} else if (options.gss_trust_dns) {
Jakub Jelen def1de
+			gss_host = remote_hostname(ssh);
Jakub Jelen 57ba1b
+			/* Fall back to specified host if we are using proxy command
Jakub Jelen 57ba1b
+			 * and can not use DNS on that socket */
Jakub Jelen 57ba1b
+			if (strcmp(gss_host, "UNKNOWN") == 0) {
Jakub Jelen 57ba1b
+				free(gss_host);
Jakub Jelen 57ba1b
+				gss_host = xstrdup(host);
Jakub Jelen 57ba1b
+			}
Jakub Jelen 57ba1b
+		} else {
Jakub Jelen def1de
+			gss_host = xstrdup(host);
Jakub Jelen 57ba1b
+		}
Jakub Jelen def1de
+
Jakub Jelen def1de
+		gss = ssh_gssapi_client_mechanisms(gss_host,
Jakub Jelen def1de
+		    options.gss_client_identity, options.gss_kex_algorithms);
Jakub Jelen def1de
+		if (gss) {
Jakub Jelen def1de
+			debug("Offering GSSAPI proposal: %s", gss);
Jakub Jelen def1de
+			xasprintf(&myproposal[PROPOSAL_KEX_ALGS],
Jakub Jelen def1de
+			    "%s,%s", gss, orig);
Jakub Jelen def1de
+
Jakub Jelen def1de
+			/* If we've got GSSAPI algorithms, then we also support the
Jakub Jelen def1de
+			 * 'null' hostkey, as a last resort */
Jakub Jelen def1de
+			orig = myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS];
Jakub Jelen def1de
+			xasprintf(&myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS],
Jakub Jelen def1de
+			    "%s,null", orig);
Jakub Jelen def1de
+		}
Jakub Jelen def1de
+	}
Jakub Jelen def1de
+#endif
Jakub Jelen def1de
+
Jakub Jelen def1de
 	if (options.rekey_limit || options.rekey_interval)
Jakub Jelen def1de
 		ssh_packet_set_rekey_limits(ssh, options.rekey_limit,
Jakub Jelen def1de
 		    options.rekey_interval);
Jakub Jelen 51f5c1
@@ -224,16 +256,46 @@ ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port)
Jakub Jelen def1de
 # ifdef OPENSSL_HAS_ECC
Jakub Jelen def1de
 	ssh->kex->kex[KEX_ECDH_SHA2] = kex_gen_client;
Jakub Jelen def1de
 # endif
Jakub Jelen def1de
-#endif
Jakub Jelen def1de
+# ifdef GSSAPI
Jakub Jelen def1de
+	if (options.gss_keyex) {
Jakub Jelen def1de
+		ssh->kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_client;
Jakub Jelen def1de
+		ssh->kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_client;
Jakub Jelen def1de
+		ssh->kex->kex[KEX_GSS_GRP14_SHA256] = kexgss_client;
Jakub Jelen def1de
+		ssh->kex->kex[KEX_GSS_GRP16_SHA512] = kexgss_client;
Jakub Jelen def1de
+		ssh->kex->kex[KEX_GSS_GEX_SHA1] = kexgssgex_client;
Jakub Jelen def1de
+		ssh->kex->kex[KEX_GSS_NISTP256_SHA256] = kexgss_client;
Jakub Jelen def1de
+		ssh->kex->kex[KEX_GSS_C25519_SHA256] = kexgss_client;
Jakub Jelen def1de
+	}
Jakub Jelen def1de
+# endif
Jakub Jelen def1de
+#endif /* WITH_OPENSSL */
Jakub Jelen def1de
 	ssh->kex->kex[KEX_C25519_SHA256] = kex_gen_client;
Jakub Jelen def1de
 	ssh->kex->kex[KEX_KEM_SNTRUP4591761X25519_SHA512] = kex_gen_client;
Jakub Jelen def1de
 	ssh->kex->verify_host_key=&verify_host_key_callback;
Jakub Jelen def1de
 
Jakub Jelen def1de
+#if defined(GSSAPI) && defined(WITH_OPENSSL)
Jakub Jelen def1de
+	if (options.gss_keyex) {
Jakub Jelen def1de
+		ssh->kex->gss_deleg_creds = options.gss_deleg_creds;
Jakub Jelen def1de
+		ssh->kex->gss_trust_dns = options.gss_trust_dns;
Jakub Jelen def1de
+		ssh->kex->gss_client = options.gss_client_identity;
Jakub Jelen def1de
+		ssh->kex->gss_host = gss_host;
Jakub Jelen def1de
+	}
Jakub Jelen def1de
+#endif
Jakub Jelen def1de
+
Jakub Jelen def1de
 	ssh_dispatch_run_fatal(ssh, DISPATCH_BLOCK, &ssh->kex->done);
Jakub Jelen def1de
 
Jakub Jelen def1de
 	/* remove ext-info from the KEX proposals for rekeying */
Jakub Jelen def1de
 	myproposal[PROPOSAL_KEX_ALGS] =
Jakub Jelen def1de
 	    compat_kex_proposal(options.kex_algorithms);
Jakub Jelen def1de
+#if defined(GSSAPI) && defined(WITH_OPENSSL)
Jakub Jelen def1de
+	/* repair myproposal after it was crumpled by the */
Jakub Jelen def1de
+	/* ext-info removal above */
Jakub Jelen def1de
+	if (gss) {
Jakub Jelen def1de
+		orig = myproposal[PROPOSAL_KEX_ALGS];
Jakub Jelen def1de
+		xasprintf(&myproposal[PROPOSAL_KEX_ALGS],
Jakub Jelen def1de
+		    "%s,%s", gss, orig);
Jakub Jelen def1de
+		free(gss);
Jakub Jelen def1de
+	}
Jakub Jelen def1de
+#endif
Jakub Jelen def1de
 	if ((r = kex_prop2buf(ssh->kex->my, myproposal)) != 0)
Jakub Jelen def1de
 		fatal("kex_prop2buf: %s", ssh_err(r));
Jakub Jelen def1de
 
Jakub Jelen 51f5c1
@@ -330,6 +392,7 @@ static int input_gssapi_response(int type, u_int32_t, struct ssh *);
Jakub Jelen def1de
 static int input_gssapi_token(int type, u_int32_t, struct ssh *);
Jakub Jelen def1de
 static int input_gssapi_error(int, u_int32_t, struct ssh *);
Jakub Jelen def1de
 static int input_gssapi_errtok(int, u_int32_t, struct ssh *);
Jakub Jelen def1de
+static int userauth_gsskeyex(struct ssh *);
Jakub Jelen def1de
 #endif
Jakub Jelen def1de
 
Jakub Jelen def1de
 void	userauth(struct ssh *, char *);
Jakub Jelen 51f5c1
@@ -346,6 +409,11 @@ static char *authmethods_get(void);
Jakub Jelen def1de
 
Jakub Jelen def1de
 Authmethod authmethods[] = {
Jakub Jelen def1de
 #ifdef GSSAPI
Jakub Jelen def1de
+	{"gssapi-keyex",
Jakub Jelen def1de
+		userauth_gsskeyex,
Jakub Jelen def1de
+		NULL,
Jakub Jelen def1de
+		&options.gss_keyex,
Jakub Jelen def1de
+		NULL},
Jakub Jelen def1de
 	{"gssapi-with-mic",
Jakub Jelen def1de
 		userauth_gssapi,
Jakub Jelen def1de
 		userauth_gssapi_cleanup,
Jakub Jelen 57ba1b
@@ -716,12 +784,32 @@ userauth_gssapi(struct ssh *ssh)
Jakub Jelen def1de
 	OM_uint32 min;
Jakub Jelen def1de
 	int r, ok = 0;
Jakub Jelen def1de
 	gss_OID mech = NULL;
Jakub Jelen 57ba1b
+	char *gss_host = NULL;
Jakub Jelen def1de
+
Jakub Jelen 57ba1b
+	if (options.gss_server_identity) {
Jakub Jelen def1de
+		gss_host = xstrdup(options.gss_server_identity);
Jakub Jelen 57ba1b
+	} else if (options.gss_trust_dns) {
Jakub Jelen def1de
+		gss_host = remote_hostname(ssh);
Jakub Jelen 57ba1b
+		/* Fall back to specified host if we are using proxy command
Jakub Jelen 57ba1b
+		 * and can not use DNS on that socket */
Jakub Jelen 57ba1b
+		if (strcmp(gss_host, "UNKNOWN") == 0) {
Jakub Jelen 57ba1b
+			free(gss_host);
Jakub Jelen 57ba1b
+			gss_host = xstrdup(authctxt->host);
Jakub Jelen 57ba1b
+		}
Jakub Jelen 57ba1b
+	} else {
Jakub Jelen def1de
+		gss_host = xstrdup(authctxt->host);
Jakub Jelen 57ba1b
+	}
Jakub Jelen def1de
 
Jakub Jelen def1de
 	/* Try one GSSAPI method at a time, rather than sending them all at
Jakub Jelen def1de
 	 * once. */
Jakub Jelen def1de
 
Jakub Jelen def1de
 	if (authctxt->gss_supported_mechs == NULL)
Jakub Jelen def1de
-		gss_indicate_mechs(&min, &authctxt->gss_supported_mechs);
Jakub Jelen 51f5c1
+		if (GSS_ERROR(gss_indicate_mechs(&min,
Jakub Jelen 51f5c1
+		    &authctxt->gss_supported_mechs))) {
Jakub Jelen 51f5c1
+			authctxt->gss_supported_mechs = NULL;
Jakub Jelen def1de
+			free(gss_host);
Jakub Jelen def1de
+			return 0;
Jakub Jelen def1de
+		}
Jakub Jelen def1de
 
Jakub Jelen def1de
 	/* Check to see whether the mechanism is usable before we offer it */
Jakub Jelen def1de
 	while (authctxt->mech_tried < authctxt->gss_supported_mechs->count &&
Jakub Jelen 51f5c1
@@ -730,13 +811,15 @@ userauth_gssapi(struct ssh *ssh)
Jakub Jelen def1de
 		    elements[authctxt->mech_tried];
Jakub Jelen def1de
 		/* My DER encoding requires length<128 */
Jakub Jelen def1de
 		if (mech->length < 128 && ssh_gssapi_check_mechanism(&gssctxt,
Jakub Jelen def1de
-		    mech, authctxt->host)) {
Jakub Jelen def1de
+		    mech, gss_host, options.gss_client_identity)) {
Jakub Jelen def1de
 			ok = 1; /* Mechanism works */
Jakub Jelen def1de
 		} else {
Jakub Jelen def1de
 			authctxt->mech_tried++;
Jakub Jelen def1de
 		}
Jakub Jelen def1de
 	}
Jakub Jelen def1de
 
Jakub Jelen def1de
+	free(gss_host);
Jakub Jelen def1de
+
Jakub Jelen def1de
 	if (!ok || mech == NULL)
Jakub Jelen def1de
 		return 0;
Jakub Jelen def1de
 
Jakub Jelen 51f5c1
@@ -976,6 +1059,55 @@ input_gssapi_error(int type, u_int32_t plen, struct ssh *ssh)
Jakub Jelen def1de
 	free(lang);
Jakub Jelen def1de
 	return r;
Jakub Jelen def1de
 }
Jakub Jelen def1de
+
Jakub Jelen def1de
+int
Jakub Jelen def1de
+userauth_gsskeyex(struct ssh *ssh)
Jakub Jelen def1de
+{
Jakub Jelen def1de
+	struct sshbuf *b = NULL;
Jakub Jelen def1de
+	Authctxt *authctxt = ssh->authctxt;
Jakub Jelen def1de
+	gss_buffer_desc gssbuf;
Jakub Jelen def1de
+	gss_buffer_desc mic = GSS_C_EMPTY_BUFFER;
Jakub Jelen def1de
+	OM_uint32 ms;
Jakub Jelen def1de
+	int r;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	static int attempt = 0;
Jakub Jelen def1de
+	if (attempt++ >= 1)
Jakub Jelen def1de
+		return (0);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if (gss_kex_context == NULL) {
Jakub Jelen def1de
+		debug("No valid Key exchange context");
Jakub Jelen def1de
+		return (0);
Jakub Jelen def1de
+	}
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if ((b = sshbuf_new()) == NULL)
Jakub Jelen def1de
+		fatal("%s: sshbuf_new failed", __func__);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	ssh_gssapi_buildmic(b, authctxt->server_user, authctxt->service,
Jakub Jelen def1de
+	    "gssapi-keyex");
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if ((gssbuf.value = sshbuf_mutable_ptr(b)) == NULL)
Jakub Jelen def1de
+		fatal("%s: sshbuf_mutable_ptr failed", __func__);
Jakub Jelen def1de
+	gssbuf.length = sshbuf_len(b);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if (GSS_ERROR(ssh_gssapi_sign(gss_kex_context, &gssbuf, &mic))) {
Jakub Jelen def1de
+		sshbuf_free(b);
Jakub Jelen def1de
+		return (0);
Jakub Jelen def1de
+	}
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_REQUEST)) != 0 ||
Jakub Jelen def1de
+	    (r = sshpkt_put_cstring(ssh, authctxt->server_user)) != 0 ||
Jakub Jelen def1de
+	    (r = sshpkt_put_cstring(ssh, authctxt->service)) != 0 ||
Jakub Jelen def1de
+	    (r = sshpkt_put_cstring(ssh, authctxt->method->name)) != 0 ||
Jakub Jelen def1de
+	    (r = sshpkt_put_string(ssh, mic.value, mic.length)) != 0 ||
Jakub Jelen def1de
+	    (r = sshpkt_send(ssh)) != 0)
Jakub Jelen def1de
+		fatal("%s: %s", __func__, ssh_err(r));
Jakub Jelen def1de
+
Jakub Jelen def1de
+	sshbuf_free(b);
Jakub Jelen def1de
+	gss_release_buffer(&ms, &mic);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	return (1);
Jakub Jelen def1de
+}
Jakub Jelen def1de
+
Jakub Jelen def1de
 #endif /* GSSAPI */
Jakub Jelen def1de
 
Jakub Jelen def1de
 static int
Jakub Jelen def1de
diff --git a/sshd.c b/sshd.c
Jakub Jelen 51f5c1
index 60b2aaf7..d92f03aa 100644
Jakub Jelen def1de
--- a/sshd.c
Jakub Jelen def1de
+++ b/sshd.c
Jakub Jelen 51f5c1
@@ -817,8 +817,8 @@ notify_hostkeys(struct ssh *ssh)
Jakub Jelen def1de
 	}
Jakub Jelen def1de
 	debug3("%s: sent %u hostkeys", __func__, nkeys);
Jakub Jelen def1de
 	if (nkeys == 0)
Jakub Jelen def1de
-		fatal("%s: no hostkeys", __func__);
Jakub Jelen def1de
-	if ((r = sshpkt_send(ssh)) != 0)
Jakub Jelen def1de
+		debug3("%s: no hostkeys", __func__);
Jakub Jelen def1de
+	else if ((r = sshpkt_send(ssh)) != 0)
Jakub Jelen def1de
 		sshpkt_fatal(ssh, r, "%s: send", __func__);
Jakub Jelen def1de
 	sshbuf_free(buf);
Jakub Jelen def1de
 }
Jakub Jelen 51f5c1
@@ -1852,7 +1852,8 @@ main(int ac, char **av)
Jakub Jelen def1de
 		free(fp);
Jakub Jelen def1de
 	}
Jakub Jelen def1de
 	accumulate_host_timing_secret(cfg, NULL);
Jakub Jelen def1de
-	if (!sensitive_data.have_ssh2_key) {
Jakub Jelen def1de
+	/* The GSSAPI key exchange can run without a host key */
Jakub Jelen def1de
+	if (!sensitive_data.have_ssh2_key && !options.gss_keyex) {
Jakub Jelen def1de
 		logit("sshd: no hostkeys available -- exiting.");
Jakub Jelen def1de
 		exit(1);
Jakub Jelen def1de
 	}
Jakub Jelen 51f5c1
@@ -2347,6 +2348,48 @@ do_ssh2_kex(struct ssh *ssh)
Jakub Jelen def1de
 	myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = compat_pkalg_proposal(
Jakub Jelen def1de
 	    list_hostkey_types());
Jakub Jelen def1de
 
Jakub Jelen def1de
+#if defined(GSSAPI) && defined(WITH_OPENSSL)
Jakub Jelen def1de
+	{
Jakub Jelen def1de
+	char *orig;
Jakub Jelen def1de
+	char *gss = NULL;
Jakub Jelen def1de
+	char *newstr = NULL;
Jakub Jelen def1de
+	orig = myproposal[PROPOSAL_KEX_ALGS];
Jakub Jelen def1de
+
Jakub Jelen def1de
+	/*
Jakub Jelen def1de
+	 * If we don't have a host key, then there's no point advertising
Jakub Jelen def1de
+	 * the other key exchange algorithms
Jakub Jelen def1de
+	 */
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]) == 0)
Jakub Jelen def1de
+		orig = NULL;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if (options.gss_keyex)
Jakub Jelen def1de
+		gss = ssh_gssapi_server_mechanisms();
Jakub Jelen def1de
+	else
Jakub Jelen def1de
+		gss = NULL;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if (gss && orig)
Jakub Jelen def1de
+		xasprintf(&newstr, "%s,%s", gss, orig);
Jakub Jelen def1de
+	else if (gss)
Jakub Jelen def1de
+		newstr = gss;
Jakub Jelen def1de
+	else if (orig)
Jakub Jelen def1de
+		newstr = orig;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	/*
Jakub Jelen def1de
+	 * If we've got GSSAPI mechanisms, then we've got the 'null' host
Jakub Jelen def1de
+	 * key alg, but we can't tell people about it unless its the only
Jakub Jelen def1de
+	 * host key algorithm we support
Jakub Jelen def1de
+	 */
Jakub Jelen def1de
+	if (gss && (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS])) == 0)
Jakub Jelen def1de
+		myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = "null";
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if (newstr)
Jakub Jelen def1de
+		myproposal[PROPOSAL_KEX_ALGS] = newstr;
Jakub Jelen def1de
+	else
Jakub Jelen def1de
+		fatal("No supported key exchange algorithms");
Jakub Jelen def1de
+	}
Jakub Jelen def1de
+#endif
Jakub Jelen def1de
+
Jakub Jelen def1de
 	/* start key exchange */
Jakub Jelen def1de
 	if ((r = kex_setup(ssh, myproposal)) != 0)
Jakub Jelen def1de
 		fatal("kex_setup: %s", ssh_err(r));
Jakub Jelen 51f5c1
@@ -2362,7 +2405,18 @@ do_ssh2_kex(struct ssh *ssh)
Jakub Jelen def1de
 # ifdef OPENSSL_HAS_ECC
Jakub Jelen def1de
 	kex->kex[KEX_ECDH_SHA2] = kex_gen_server;
Jakub Jelen def1de
 # endif
Jakub Jelen def1de
-#endif
Jakub Jelen def1de
+# ifdef GSSAPI
Jakub Jelen def1de
+	if (options.gss_keyex) {
Jakub Jelen def1de
+		kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server;
Jakub Jelen def1de
+		kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_server;
Jakub Jelen def1de
+		kex->kex[KEX_GSS_GRP14_SHA256] = kexgss_server;
Jakub Jelen def1de
+		kex->kex[KEX_GSS_GRP16_SHA512] = kexgss_server;
Jakub Jelen def1de
+		kex->kex[KEX_GSS_GEX_SHA1] = kexgssgex_server;
Jakub Jelen def1de
+		kex->kex[KEX_GSS_NISTP256_SHA256] = kexgss_server;
Jakub Jelen def1de
+		kex->kex[KEX_GSS_C25519_SHA256] = kexgss_server;
Jakub Jelen def1de
+	}
Jakub Jelen def1de
+# endif
Jakub Jelen def1de
+#endif /* WITH_OPENSSL */
Jakub Jelen def1de
 	kex->kex[KEX_C25519_SHA256] = kex_gen_server;
Jakub Jelen def1de
 	kex->kex[KEX_KEM_SNTRUP4591761X25519_SHA512] = kex_gen_server;
Jakub Jelen def1de
 	kex->load_host_public_key=&get_hostkey_public_by_type;
Jakub Jelen def1de
diff --git a/sshd_config b/sshd_config
Jakub Jelen def1de
index 19b7c91a..2c48105f 100644
Jakub Jelen def1de
--- a/sshd_config
Jakub Jelen def1de
+++ b/sshd_config
Jakub Jelen def1de
@@ -69,6 +69,8 @@ AuthorizedKeysFile	.ssh/authorized_keys
Jakub Jelen def1de
 # GSSAPI options
Jakub Jelen 51f5c1
 #GSSAPIAuthentication no
Jakub Jelen 51f5c1
 #GSSAPICleanupCredentials yes
Jakub Jelen def1de
+#GSSAPIStrictAcceptorCheck yes
Jakub Jelen def1de
+#GSSAPIKeyExchange no
Jakub Jelen def1de
 
Jakub Jelen def1de
 # Set this to 'yes' to enable PAM authentication, account processing,
Jakub Jelen def1de
 # and session processing. If this is enabled, PAM authentication will
Jakub Jelen def1de
diff --git a/sshd_config.5 b/sshd_config.5
Jakub Jelen 51f5c1
index 70ccea44..f6b41a2f 100644
Jakub Jelen def1de
--- a/sshd_config.5
Jakub Jelen def1de
+++ b/sshd_config.5
Jakub Jelen 51f5c1
@@ -646,6 +646,11 @@ Specifies whether to automatically destroy the user's credentials cache
Jakub Jelen def1de
 on logout.
Jakub Jelen def1de
 The default is
Jakub Jelen def1de
 .Cm yes .
Jakub Jelen def1de
+.It Cm GSSAPIKeyExchange
Jakub Jelen def1de
+Specifies whether key exchange based on GSSAPI is allowed. GSSAPI key exchange
Jakub Jelen def1de
+doesn't rely on ssh keys to verify host identity.
Jakub Jelen def1de
+The default is
Jakub Jelen def1de
+.Cm no .
Jakub Jelen def1de
 .It Cm GSSAPIStrictAcceptorCheck
Jakub Jelen def1de
 Determines whether to be strict about the identity of the GSSAPI acceptor
Jakub Jelen def1de
 a client authenticates against.
Jakub Jelen 1cc7c8
@@ -660,6 +665,32 @@ machine's default store.
Jakub Jelen def1de
 This facility is provided to assist with operation on multi homed machines.
Jakub Jelen def1de
 The default is
Jakub Jelen def1de
 .Cm yes .
Jakub Jelen def1de
+.It Cm GSSAPIStoreCredentialsOnRekey
Jakub Jelen def1de
+Controls whether the user's GSSAPI credentials should be updated following a
Jakub Jelen def1de
+successful connection rekeying. This option can be used to accepted renewed
Jakub Jelen def1de
+or updated credentials from a compatible client. The default is
Jakub Jelen def1de
+.Dq no .
Jakub Jelen def1de
+.Pp
Jakub Jelen def1de
+For this to work
Jakub Jelen def1de
+.Cm GSSAPIKeyExchange
Jakub Jelen def1de
+needs to be enabled in the server and also used by the client.
Jakub Jelen def1de
+.It Cm GSSAPIKexAlgorithms
Jakub Jelen def1de
+The list of key exchange algorithms that are accepted by GSSAPI
Jakub Jelen def1de
+key exchange. Possible values are
Jakub Jelen def1de
+.Bd -literal -offset 3n
Jakub Jelen def1de
+gss-gex-sha1-,
Jakub Jelen def1de
+gss-group1-sha1-,
Jakub Jelen def1de
+gss-group14-sha1-,
Jakub Jelen def1de
+gss-group14-sha256-,
Jakub Jelen def1de
+gss-group16-sha512-,
Jakub Jelen def1de
+gss-nistp256-sha256-,
Jakub Jelen def1de
+gss-curve25519-sha256-
Jakub Jelen def1de
+.Ed
Jakub Jelen def1de
+.Pp
Jakub Jelen def1de
+The default is
Jakub Jelen 1cc7c8
+.Dq gss-group14-sha256-,gss-group16-sha512-,gss-nistp256-sha256-,
Jakub Jelen 1cc7c8
+gss-curve25519-sha256-,gss-group14-sha1-,gss-gex-sha1- .
Jakub Jelen 1cc7c8
+This option only applies to connections using GSSAPI.
Jakub Jelen def1de
 .It Cm HostbasedAcceptedKeyTypes
Jakub Jelen def1de
 Specifies the key types that will be accepted for hostbased authentication
Jakub Jelen def1de
 as a list of comma-separated patterns.
Jakub Jelen def1de
diff --git a/sshkey.c b/sshkey.c
Jakub Jelen 51f5c1
index 57995ee6..fd5b7724 100644
Jakub Jelen def1de
--- a/sshkey.c
Jakub Jelen def1de
+++ b/sshkey.c
Jakub Jelen 51f5c1
@@ -154,6 +154,7 @@ static const struct keytype keytypes[] = {
Jakub Jelen 51f5c1
 	    KEY_ECDSA_SK_CERT, NID_X9_62_prime256v1, 1, 0 },
Jakub Jelen def1de
 # endif /* OPENSSL_HAS_ECC */
Jakub Jelen def1de
 #endif /* WITH_OPENSSL */
Jakub Jelen def1de
+	{ "null", "null", NULL, KEY_NULL, 0, 0, 0 },
Jakub Jelen def1de
 	{ NULL, NULL, NULL, -1, -1, 0, 0 }
Jakub Jelen def1de
 };
Jakub Jelen def1de
 
Jakub Jelen 51f5c1
@@ -255,7 +256,7 @@ sshkey_alg_list(int certs_only, int plain_only, int include_sigonly, char sep)
Jakub Jelen def1de
 	const struct keytype *kt;
Jakub Jelen def1de
 
Jakub Jelen def1de
 	for (kt = keytypes; kt->type != -1; kt++) {
Jakub Jelen def1de
-		if (kt->name == NULL)
Jakub Jelen def1de
+		if (kt->name == NULL || kt->type == KEY_NULL)
Jakub Jelen def1de
 			continue;
Jakub Jelen def1de
 		if (!include_sigonly && kt->sigonly)
Jakub Jelen def1de
 			continue;
Jakub Jelen def1de
diff --git a/sshkey.h b/sshkey.h
Jakub Jelen 51f5c1
index 71a3fddc..37a43a67 100644
Jakub Jelen def1de
--- a/sshkey.h
Jakub Jelen def1de
+++ b/sshkey.h
Jakub Jelen 51f5c1
@@ -69,6 +69,7 @@ enum sshkey_types {
Jakub Jelen 51f5c1
 	KEY_ECDSA_SK_CERT,
Jakub Jelen 51f5c1
 	KEY_ED25519_SK,
Jakub Jelen 51f5c1
 	KEY_ED25519_SK_CERT,
Jakub Jelen def1de
+	KEY_NULL,
Jakub Jelen def1de
 	KEY_UNSPEC
Jakub Jelen def1de
 };
Jakub Jelen def1de