PSARC/2015/395 OpenSSH 7.1p1
PSARC 2014/390 OpenSSH GSSKEY
21696247 upgrade OpenSSH to 7.1p1
22031540 problem in UTILITY/OPENSSH
22022180 problem in UTILITY/OPENSSH
22048638 problem in UTILITY/OPENSSH
19775805 OpenSSH contains a redundant call to do_pam_setcred()
21379157 OpenSSH shouldn't call setproject(3PROJECT) when configured to use PAM
20919294 upgrade OpenSSH to 6.8p1
19130869 migrate the Xforwarding bug fix (15350344) from SunSSH to OpenSSH
21861322 OpenSSH client hangs on broken pipe
22018764 remove cast128-cbc from OpenSSH
21919790 add GSSKeyEx as an alias to GSSAPIKeyExchange in OpenSSH
19941148 GSS-API Key Exchange for OpenSSH
21643415 OpenSSH should use AI_ADDRCONFIG per bug 19827438
20370803 OpenSSH patch number collision
20711463 OpenSSH wants to be able to login to a role too
22389801 OpenSSH: remove cast from ssh(1), sshd(8), ssh_config(5) and sshd_config(5)
22582153 openssh system/linker should be added to core REQ
#
# GSS-API key exchange support
#
# Based on https://github.com/SimonWilkinson/gss-openssh/commit/ffae842
# Updated to apply to OpenSSH 6.5.
# Default value for GSSAPIKeyExchange changed to yes to match SunSSH behavior.
# New files kexgssc.c and kexgsss.c moved to ../sources/ and made cstyle clean.
#
# Upstream rejected GSS-API key exchange several times before.
#
diff -pur old/Makefile.in new/Makefile.in
--- old/Makefile.in 2015-12-10 14:51:47.781146370 -0800
+++ new/Makefile.in 2015-12-10 14:48:21.907121340 -0800
@@ -85,6 +85,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \
atomicio.o key.o dispatch.o mac.o uidswap.o uuencode.o misc.o \
monitor_fdpass.o rijndael.o ssh-dss.o ssh-ecdsa.o ssh-rsa.o dh.o \
msg.o progressmeter.o dns.o entropy.o gss-genr.o umac.o umac128.o \
+ kexgssc.o \
ssh-pkcs11.o smult_curve25519_ref.o \
poly1305.o chacha.o cipher-chachapoly.o \
ssh-ed25519.o digest-openssl.o digest-libc.o hmac.o \
@@ -105,7 +106,7 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passw
auth-skey.o auth-bsdauth.o auth2-hostbased.o auth2-kbdint.o \
auth2-none.o auth2-passwd.o auth2-pubkey.o \
monitor_mm.o monitor.o monitor_wrap.o auth-krb5.o \
- auth2-gss.o gss-serv.o gss-serv-krb5.o \
+ auth2-gss.o gss-serv.o gss-serv-krb5.o kexgsss.o \
loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \
sftp-server.o sftp-common.o \
roaming_common.o roaming_serv.o \
diff -pur old/auth2-gss.c new/auth2-gss.c
--- old/auth2-gss.c
+++ new/auth2-gss.c
@@ -1,7 +1,7 @@
/* $OpenBSD: auth2-gss.c,v 1.22 2015/01/19 20:07:45 markus Exp $ */
/*
- * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
+ * Copyright (c) 2001-2007 Simon Wilkinson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -53,6 +53,39 @@ static int input_gssapi_mic(int type, u_
static int input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt);
static int input_gssapi_errtok(int, u_int32_t, void *);
+/*
+ * The 'gssapi_keyex' userauth mechanism.
+ */
+static int
+userauth_gsskeyex(Authctxt *authctxt)
+{
+ int authenticated = 0;
+ Buffer b;
+ gss_buffer_desc mic, gssbuf;
+ u_int len;
+
+ mic.value = packet_get_string(&len);
+ mic.length = len;
+
+ packet_check_eom();
+
+ ssh_gssapi_buildmic(&b, authctxt->user, authctxt->service,
+ "gssapi-keyex");
+
+ gssbuf.value = buffer_ptr(&b);
+ gssbuf.length = buffer_len(&b);
+
+ /* gss_kex_context is NULL with privsep, so we can't check it here */
+ if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gss_kex_context,
+ &gssbuf, &mic))))
+ authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user));
+
+ buffer_free(&b);
+ free(mic.value);
+
+ return (authenticated);
+}
+
/*
* We only support those mechanisms that we know about (ie ones that we know
* how to check local user kuserok and the like)
@@ -290,6 +323,12 @@ input_gssapi_mic(int type, u_int32_t ple
return 0;
}
+Authmethod method_gsskeyex = {
+ "gssapi-keyex",
+ userauth_gsskeyex,
+ &options.gss_authentication
+};
+
Authmethod method_gssapi = {
"gssapi-with-mic",
userauth_gssapi,
diff -pur old/auth2.c new/auth2.c
--- old/auth2.c
+++ new/auth2.c
@@ -70,6 +70,7 @@ extern Authmethod method_passwd;
extern Authmethod method_kbdint;
extern Authmethod method_hostbased;
#ifdef GSSAPI
+extern Authmethod method_gsskeyex;
extern Authmethod method_gssapi;
#endif
@@ -77,6 +78,7 @@ Authmethod *authmethods[] = {
&method_none,
&method_pubkey,
#ifdef GSSAPI
+ &method_gsskeyex,
&method_gssapi,
#endif
&method_passwd,
diff -pur old/configure new/configure
--- old/configure
+++ new/configure
@@ -10944,8 +10944,10 @@ fi
fi
- $as_echo "#define USE_GSS_STORE_CRED 1" >>confdefs.h
- $as_echo "#define GSSAPI_STORECREDS_NEEDS_RUID 1" >>confdefs.h
+cat >>confdefs.h <<\_ACEOF
+#define USE_GSS_STORE_CRED 1
+#define GSSAPI_STORECREDS_NEEDS_RUID 1
+_ACEOF
TEST_SHELL=$SHELL # let configure find us a capable shell
;;
diff -pur old/gss-genr.c new/gss-genr.c
--- old/gss-genr.c
+++ new/gss-genr.c
@@ -1,7 +1,7 @@
/* $OpenBSD: gss-genr.c,v 1.23 2015/01/20 23:14:00 deraadt Exp $ */
/*
- * Copyright (c) 2001-2007 Simon Wilkinson. All rights reserved.
+ * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -41,12 +41,167 @@
#include "buffer.h"
#include "log.h"
#include "ssh2.h"
+#include "cipher.h"
+#include "key.h"
+#include "kex.h"
+#include <openssl/evp.h>
#include "ssh-gss.h"
extern u_char *session_id2;
extern u_int session_id2_len;
+typedef struct {
+ char *encoded;
+ gss_OID oid;
+} ssh_gss_kex_mapping;
+
+/*
+ * XXX - It would be nice to find a more elegant way of handling the
+ * XXX passing of the key exchange context to the userauth routines
+ */
+
+Gssctxt *gss_kex_context = NULL;
+
+static ssh_gss_kex_mapping *gss_enc2oid = NULL;
+
+int
+ssh_gssapi_oid_table_ok() {
+ return (gss_enc2oid != NULL);
+}
+
+/*
+ * Return a list of the gss-group1-sha1 mechanisms supported by this program
+ *
+ * We test mechanisms to ensure that we can use them, to avoid starting
+ * a key exchange with a bad mechanism
+ */
+
+char *
+ssh_gssapi_client_mechanisms(const char *host) {
+ gss_OID_set gss_supported;
+ OM_uint32 min_status;
+
+ if (GSS_ERROR(gss_indicate_mechs(&min_status, &gss_supported)))
+ return NULL;
+
+ return(ssh_gssapi_kex_mechs(gss_supported, ssh_gssapi_check_mechanism,
+ host));
+}
+
+char *
+ssh_gssapi_kex_mechs(gss_OID_set gss_supported, ssh_gssapi_check_fn *check,
+ const char *data) {
+ Buffer buf;
+ size_t i;
+ int oidpos, enclen;
+ char *mechs, *encoded;
+ u_char digest[EVP_MAX_MD_SIZE];
+ char deroid[2];
+ const EVP_MD *evp_md = EVP_md5();
+ EVP_MD_CTX md;
+
+ if (gss_enc2oid != NULL) {
+ for (i = 0; gss_enc2oid[i].encoded != NULL; i++)
+ free(gss_enc2oid[i].encoded);
+ free(gss_enc2oid);
+ }
+
+ gss_enc2oid = xmalloc(sizeof(ssh_gss_kex_mapping) *
+ (gss_supported->count + 1));
+
+ buffer_init(&buf);
+
+ oidpos = 0;
+ for (i = 0; i < gss_supported->count; i++) {
+ if (gss_supported->elements[i].length < 128 &&
+ (*check)(NULL, &(gss_supported->elements[i]), data)) {
+
+ deroid[0] = SSH_GSS_OIDTYPE;
+ deroid[1] = gss_supported->elements[i].length;
+
+ EVP_DigestInit(&md, evp_md);
+ EVP_DigestUpdate(&md, deroid, 2);
+ EVP_DigestUpdate(&md,
+ gss_supported->elements[i].elements,
+ gss_supported->elements[i].length);
+ EVP_DigestFinal(&md, digest, NULL);
+
+ encoded = xmalloc(EVP_MD_size(evp_md) * 2);
+ enclen = __b64_ntop(digest, EVP_MD_size(evp_md),
+ encoded, EVP_MD_size(evp_md) * 2);
+
+ if (oidpos != 0)
+ buffer_put_char(&buf, ',');
+
+ buffer_append(&buf, KEX_GSS_GEX_SHA1_ID,
+ sizeof(KEX_GSS_GEX_SHA1_ID) - 1);
+ buffer_append(&buf, encoded, enclen);
+ buffer_put_char(&buf, ',');
+ buffer_append(&buf, KEX_GSS_GRP1_SHA1_ID,
+ sizeof(KEX_GSS_GRP1_SHA1_ID) - 1);
+ buffer_append(&buf, encoded, enclen);
+ buffer_put_char(&buf, ',');
+ buffer_append(&buf, KEX_GSS_GRP14_SHA1_ID,
+ sizeof(KEX_GSS_GRP14_SHA1_ID) - 1);
+ buffer_append(&buf, encoded, enclen);
+
+ gss_enc2oid[oidpos].oid = &(gss_supported->elements[i]);
+ gss_enc2oid[oidpos].encoded = encoded;
+ oidpos++;
+ }
+ }
+ gss_enc2oid[oidpos].oid = NULL;
+ gss_enc2oid[oidpos].encoded = NULL;
+
+ buffer_put_char(&buf, '\0');
+
+ mechs = xmalloc(buffer_len(&buf));
+ buffer_get(&buf, mechs, buffer_len(&buf));
+ buffer_free(&buf);
+
+ if (strlen(mechs) == 0) {
+ free(mechs);
+ mechs = NULL;
+ }
+
+ return (mechs);
+}
+
+gss_OID
+ssh_gssapi_id_kex(Gssctxt *ctx, char *name, int kex_type) {
+ int i = 0;
+
+ switch (kex_type) {
+ case KEX_GSS_GRP1_SHA1:
+ if (strlen(name) < sizeof(KEX_GSS_GRP1_SHA1_ID))
+ return GSS_C_NO_OID;
+ name += sizeof(KEX_GSS_GRP1_SHA1_ID) - 1;
+ break;
+ case KEX_GSS_GRP14_SHA1:
+ if (strlen(name) < sizeof(KEX_GSS_GRP14_SHA1_ID))
+ return GSS_C_NO_OID;
+ name += sizeof(KEX_GSS_GRP14_SHA1_ID) - 1;
+ break;
+ case KEX_GSS_GEX_SHA1:
+ if (strlen(name) < sizeof(KEX_GSS_GEX_SHA1_ID))
+ return GSS_C_NO_OID;
+ name += sizeof(KEX_GSS_GEX_SHA1_ID) - 1;
+ break;
+ default:
+ return GSS_C_NO_OID;
+ }
+
+ while (gss_enc2oid[i].encoded != NULL &&
+ strcmp(name, gss_enc2oid[i].encoded) != 0)
+ i++;
+
+ if (gss_enc2oid[i].oid != NULL && ctx != NULL)
+ ssh_gssapi_set_oid(ctx, gss_enc2oid[i].oid);
+
+ return gss_enc2oid[i].oid;
+}
+
/* Check that the OID in a data stream matches that in the context */
int
ssh_gssapi_check_oid(Gssctxt *ctx, void *data, size_t len)
@@ -231,6 +386,9 @@ ssh_gssapi_import_name(Gssctxt *ctx, con
OM_uint32
ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash)
{
+ if (ctx == NULL)
+ return -1;
+
if ((ctx->major = gss_get_mic(&ctx->minor, ctx->context,
GSS_C_QOP_DEFAULT, buffer, hash)))
ssh_gssapi_error(ctx);
@@ -238,6 +396,19 @@ ssh_gssapi_sign(Gssctxt *ctx, gss_buffer
return (ctx->major);
}
+/* Priviledged when used by server */
+OM_uint32
+ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic)
+{
+ if (ctx == NULL)
+ return -1;
+
+ ctx->major = gss_verify_mic(&ctx->minor, ctx->context,
+ gssbuf, gssmic, NULL);
+
+ return (ctx->major);
+}
+
void
ssh_gssapi_buildmic(Buffer *b, const char *user, const char *service,
const char *context)
@@ -256,6 +427,10 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx
gss_buffer_desc token = GSS_C_EMPTY_BUFFER;
OM_uint32 major, minor;
gss_OID_desc spnego_oid = {6, (void *)"\x2B\x06\x01\x05\x05\x02"};
+ Gssctxt *intctx = NULL;
+
+ if (ctx == NULL)
+ ctx = &intctx;
/* RFC 4462 says we MUST NOT do SPNEGO */
if (oid->length == spnego_oid.length &&
@@ -274,7 +449,7 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx
GSS_C_NO_BUFFER);
}
- if (GSS_ERROR(major))
+ if (GSS_ERROR(major) || intctx != NULL)
ssh_gssapi_delete_ctx(ctx);
return (!GSS_ERROR(major));
diff -pur old/gss-serv.c new/gss-serv.c
--- old/gss-serv.c
+++ new/gss-serv.c
@@ -1,7 +1,7 @@
/* $OpenBSD: gss-serv.c,v 1.29 2015/05/22 03:50:02 djm Exp $ */
/*
- * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
+ * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -47,6 +47,7 @@
#include "servconf.h"
#include "ssh-gss.h"
+#include "monitor_wrap.h"
extern ServerOptions options;
@@ -142,6 +143,28 @@ ssh_gssapi_server_ctx(Gssctxt **ctx, gss
}
/* Unprivileged */
+char *
+ssh_gssapi_server_mechanisms() {
+ gss_OID_set supported;
+
+ ssh_gssapi_supported_oids(&supported);
+ return (ssh_gssapi_kex_mechs(supported, &ssh_gssapi_server_check_mech,
+ NULL));
+}
+
+/* Unprivileged */
+int
+ssh_gssapi_server_check_mech(Gssctxt **dum, gss_OID oid, const char *data) {
+ Gssctxt *ctx = NULL;
+ int res;
+
+ res = !GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctx, oid)));
+ ssh_gssapi_delete_ctx(&ctx);
+
+ return (res);
+}
+
+/* Unprivileged */
void
ssh_gssapi_supported_oids(gss_OID_set *oidset)
{
@@ -151,7 +174,9 @@ ssh_gssapi_supported_oids(gss_OID_set *o
gss_OID_set supported;
gss_create_empty_oid_set(&min_status, oidset);
- gss_indicate_mechs(&min_status, &supported);
+
+ if (GSS_ERROR(gss_indicate_mechs(&min_status, &supported)))
+ return;
while (supported_mechs[i]->name != NULL) {
if (GSS_ERROR(gss_test_oid_set_member(&min_status,
@@ -427,14 +452,4 @@ ssh_gssapi_userok(char *user)
return (0);
}
-/* Privileged */
-OM_uint32
-ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic)
-{
- ctx->major = gss_verify_mic(&ctx->minor, ctx->context,
- gssbuf, gssmic, NULL);
-
- return (ctx->major);
-}
-
#endif
diff -pur old/kex.c new/kex.c
--- old/kex.c
+++ new/kex.c
@@ -55,6 +55,10 @@
#include "sshbuf.h"
#include "digest.h"
+#ifdef GSSAPI
+#include "ssh-gss.h"
+#endif
+
#if OPENSSL_VERSION_NUMBER >= 0x00907000L
# if defined(HAVE_EVP_SHA256)
# define evp_ssh_sha256 EVP_sha256
@@ -95,6 +99,11 @@ static const struct kexalg kexalgs[] = {
#if defined(HAVE_EVP_SHA256) || !defined(WITH_OPENSSL)
{ KEX_CURVE25519_SHA256, KEX_C25519_SHA256, 0, SSH_DIGEST_SHA256 },
#endif /* HAVE_EVP_SHA256 || !WITH_OPENSSL */
+#ifdef GSSAPI
+ { KEX_GSS_GEX_SHA1_ID, KEX_GSS_GEX_SHA1, 0, SSH_DIGEST_SHA1 },
+ { KEX_GSS_GRP1_SHA1_ID, KEX_GSS_GRP1_SHA1, 0, SSH_DIGEST_SHA1 },
+ { KEX_GSS_GRP14_SHA1_ID, KEX_GSS_GRP14_SHA1, 0, SSH_DIGEST_SHA1 },
+#endif
{ NULL, -1, -1, -1},
};
@@ -126,7 +135,7 @@ kex_alg_by_name(const char *name)
const struct kexalg *k;
for (k = kexalgs; k->name != NULL; k++) {
- if (strcmp(k->name, name) == 0)
+ if (strncmp(k->name, name, strlen(k->name)) == 0)
return k;
}
return NULL;
diff -pur old/kex.h new/kex.h
--- old/kex.h
+++ new/kex.h
@@ -93,6 +93,9 @@ enum kex_exchange {
KEX_DH_GEX_SHA256,
KEX_ECDH_SHA2,
KEX_C25519_SHA256,
+ KEX_GSS_GRP1_SHA1,
+ KEX_GSS_GRP14_SHA1,
+ KEX_GSS_GEX_SHA1,
KEX_MAX
};
@@ -139,6 +142,10 @@ struct kex {
u_int flags;
int hash_alg;
int ec_nid;
+#ifdef GSSAPI
+ int gss_deleg_creds;
+ char *gss_host;
+#endif
char *client_version_string;
char *server_version_string;
char *failed_choice;
@@ -186,6 +193,10 @@ int kexecdh_client(struct ssh *);
int kexecdh_server(struct ssh *);
int kexc25519_client(struct ssh *);
int kexc25519_server(struct ssh *);
+#ifdef GSSAPI
+int kexgss_client(struct ssh *);
+int kexgss_server(struct ssh *);
+#endif
int kex_dh_hash(const char *, const char *,
const u_char *, size_t, const u_char *, size_t, const u_char *, size_t,
diff -pur old/monitor.c new/monitor.c
--- old/monitor.c
+++ new/monitor.c
@@ -160,6 +160,7 @@ int mm_answer_gss_setup_ctx(int, Buffer
int mm_answer_gss_accept_ctx(int, Buffer *);
int mm_answer_gss_userok(int, Buffer *);
int mm_answer_gss_checkmic(int, Buffer *);
+int mm_answer_gss_sign(int, Buffer *);
#endif
#ifdef SSH_AUDIT_EVENTS
@@ -244,11 +245,17 @@ struct mon_table mon_dispatch_proto20[]
{MONITOR_REQ_GSSSTEP, MON_ISAUTH, mm_answer_gss_accept_ctx},
{MONITOR_REQ_GSSUSEROK, MON_AUTH, mm_answer_gss_userok},
{MONITOR_REQ_GSSCHECKMIC, MON_ISAUTH, mm_answer_gss_checkmic},
+ {MONITOR_REQ_GSSSIGN, MON_ONCE, mm_answer_gss_sign},
#endif
{0, 0, NULL}
};
struct mon_table mon_dispatch_postauth20[] = {
+#ifdef GSSAPI
+ {MONITOR_REQ_GSSSETUP, 0, mm_answer_gss_setup_ctx},
+ {MONITOR_REQ_GSSSTEP, 0, mm_answer_gss_accept_ctx},
+ {MONITOR_REQ_GSSSIGN, 0, mm_answer_gss_sign},
+#endif
#ifdef WITH_OPENSSL
{MONITOR_REQ_MODULI, 0, mm_answer_moduli},
#endif
@@ -363,6 +370,10 @@ monitor_child_preauth(Authctxt *_authctx
/* Permit requests for moduli and signatures */
monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1);
monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1);
+#ifdef GSSAPI
+ /* and for the GSSAPI key exchange */
+ monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1);
+#endif
} else {
mon_dispatch = mon_dispatch_proto15;
@@ -502,6 +513,10 @@ monitor_child_postauth(struct monitor *p
monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1);
monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1);
monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1);
+#ifdef GSSAPI
+ /* and for the GSSAPI key exchange */
+ monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1);
+#endif
} else {
mon_dispatch = mon_dispatch_postauth15;
monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1);
@@ -1927,6 +1942,13 @@ monitor_apply_keystate(struct monitor *p
# endif
#endif /* WITH_OPENSSL */
kex->kex[KEX_C25519_SHA256] = kexc25519_server;
+#ifdef GSSAPI
+ if (options.gss_keyex) {
+ kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server;
+ kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_server;
+ kex->kex[KEX_GSS_GEX_SHA1] = kexgss_server;
+ }
+#endif
kex->load_host_public_key=&get_hostkey_public_by_type;
kex->load_host_private_key=&get_hostkey_private_by_type;
kex->host_key_index=&get_hostkey_index;
@@ -2026,6 +2048,9 @@ mm_answer_gss_setup_ctx(int sock, Buffer
OM_uint32 major;
u_int len;
+ if (!options.gss_authentication && !options.gss_keyex)
+ fatal("In GSSAPI monitor when GSSAPI is disabled");
+
goid.elements = buffer_get_string(m, &len);
goid.length = len;
@@ -2053,6 +2078,9 @@ mm_answer_gss_accept_ctx(int sock, Buffe
OM_uint32 flags = 0; /* GSI needs this */
u_int len;
+ if (!options.gss_authentication && !options.gss_keyex)
+ fatal("In GSSAPI monitor when GSSAPI is disabled");
+
in.value = buffer_get_string(m, &len);
in.length = len;
major = ssh_gssapi_accept_ctx(gsscontext, &in, &out, &flags);
@@ -2070,6 +2098,7 @@ mm_answer_gss_accept_ctx(int sock, Buffe
monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 0);
monitor_permit(mon_dispatch, MONITOR_REQ_GSSUSEROK, 1);
monitor_permit(mon_dispatch, MONITOR_REQ_GSSCHECKMIC, 1);
+ monitor_permit(mon_dispatch, MONITOR_REQ_GSSSIGN, 1);
}
return (0);
}
@@ -2081,6 +2110,9 @@ mm_answer_gss_checkmic(int sock, Buffer
OM_uint32 ret;
u_int len;
+ if (!options.gss_authentication && !options.gss_keyex)
+ fatal("In GSSAPI monitor when GSSAPI is disabled");
+
gssbuf.value = buffer_get_string(m, &len);
gssbuf.length = len;
mic.value = buffer_get_string(m, &len);
@@ -2107,6 +2139,9 @@ mm_answer_gss_userok(int sock, Buffer *m
{
int authenticated;
+ if (!options.gss_authentication && !options.gss_keyex)
+ fatal("In GSSAPI monitor when GSSAPI is disabled");
+
authenticated = authctxt->valid && ssh_gssapi_userok(authctxt->user);
buffer_clear(m);
@@ -2120,5 +2155,47 @@ mm_answer_gss_userok(int sock, Buffer *m
/* Monitor loop will terminate if authenticated */
return (authenticated);
}
+
+int
+mm_answer_gss_sign(int socket, Buffer *m)
+{
+ gss_buffer_desc data;
+ gss_buffer_desc hash = GSS_C_EMPTY_BUFFER;
+ OM_uint32 major, minor;
+ u_int len;
+
+ if (!options.gss_authentication && !options.gss_keyex)
+ fatal("In GSSAPI monitor when GSSAPI is disabled");
+
+ data.value = buffer_get_string(m, &len);
+ data.length = len;
+ if (data.length != 20)
+ fatal("%s: data length incorrect: %d", __func__,
+ (int) data.length);
+
+ /* Save the session ID on the first time around */
+ if (session_id2_len == 0) {
+ session_id2_len = data.length;
+ session_id2 = xmalloc(session_id2_len);
+ memcpy(session_id2, data.value, session_id2_len);
+ }
+ major = ssh_gssapi_sign(gsscontext, &data, &hash);
+
+ free(data.value);
+
+ buffer_clear(m);
+ buffer_put_int(m, major);
+ buffer_put_string(m, hash.value, hash.length);
+
+ mm_request_send(socket, MONITOR_ANS_GSSSIGN, m);
+
+ gss_release_buffer(&minor, &hash);
+
+ /* Turn on getpwnam permissions */
+ monitor_permit(mon_dispatch, MONITOR_REQ_PWNAM, 1);
+
+ return (0);
+}
+
#endif /* GSSAPI */
diff -pur old/monitor.h new/monitor.h
--- old/monitor.h
+++ new/monitor.h
@@ -68,6 +68,9 @@ enum monitor_reqtype {
#ifdef PAM_ENHANCEMENT
MONITOR_REQ_AUTHMETHOD = 114,
#endif
+#ifdef GSSAPI
+ MONITOR_REQ_GSSSIGN = 130, MONITOR_ANS_GSSSIGN = 131,
+#endif
};
struct mm_master;
diff -pur old/monitor_wrap.c new/monitor_wrap.c
--- old/monitor_wrap.c
+++ new/monitor_wrap.c
@@ -1103,5 +1103,28 @@ mm_ssh_gssapi_userok(char *user)
debug3("%s: user %sauthenticated",__func__, authenticated ? "" : "not ");
return (authenticated);
}
+
+OM_uint32
+mm_ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_desc *data, gss_buffer_desc *hash)
+{
+ Buffer m;
+ OM_uint32 major;
+ u_int len;
+
+ buffer_init(&m);
+ buffer_put_string(&m, data->value, data->length);
+
+ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSSIGN, &m);
+ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSSIGN, &m);
+
+ major = buffer_get_int(&m);
+ hash->value = buffer_get_string(&m, &len);
+ hash->length = len;
+
+ buffer_free(&m);
+
+ return(major);
+}
+
#endif /* GSSAPI */
diff -pur old/monitor_wrap.h new/monitor_wrap.h
--- old/monitor_wrap.h
+++ new/monitor_wrap.h
@@ -60,6 +60,7 @@ OM_uint32 mm_ssh_gssapi_accept_ctx(Gssct
gss_buffer_desc *, gss_buffer_desc *, OM_uint32 *);
int mm_ssh_gssapi_userok(char *user);
OM_uint32 mm_ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t);
+OM_uint32 mm_ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t);
#endif
#ifdef USE_PAM
diff -pur old/readconf.c new/readconf.c
--- old/readconf.c
+++ new/readconf.c
@@ -147,6 +147,7 @@ typedef enum {
oClearAllForwardings, oNoHostAuthenticationForLocalhost,
oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
oAddressFamily, oGssAuthentication, oGssDelegateCreds,
+ oGssKeyEx,
oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
oSendEnv, oControlPath, oControlMaster, oControlPersist,
oHashKnownHosts,
@@ -198,11 +199,15 @@ static struct {
{ "gssauthentication", oGssAuthentication }, /* alias */
{ "gssapidelegatecredentials", oGssDelegateCreds },
{ "gssdelegatecreds", oGssDelegateCreds }, /* alias */
+ { "gssapikeyexchange", oGssKeyEx },
+ { "gsskeyex", oGssKeyEx }, /* alias */
#else
{ "gssapiauthentication", oUnsupported },
{ "gssauthentication", oUnsupported },
{ "gssapidelegatecredentials", oUnsupported },
{ "gssdelegatecreds", oUnsupported },
+ { "gssapikeyexchange", oUnsupported },
+ { "gsskeyex", oUnsupported },
#endif
{ "fallbacktorsh", oDeprecated },
{ "usersh", oDeprecated },
@@ -933,6 +938,10 @@ parse_time:
intptr = &options->gss_authentication;
goto parse_flag;
+ case oGssKeyEx:
+ intptr = &options->gss_keyex;
+ goto parse_flag;
+
case oGssDelegateCreds:
intptr = &options->gss_deleg_creds;
goto parse_flag;
@@ -1647,6 +1656,7 @@ initialize_options(Options * options)
options->pubkey_authentication = -1;
options->challenge_response_authentication = -1;
options->gss_authentication = -1;
+ options->gss_keyex = -1;
options->gss_deleg_creds = -1;
options->password_authentication = -1;
options->kbd_interactive_authentication = -1;
@@ -1786,6 +1796,12 @@ fill_default_options(Options * options)
#else
options->gss_authentication = 0;
#endif
+ if (options->gss_keyex == -1)
+#ifdef OPTION_DEFAULT_VALUE
+ options->gss_keyex = 1;
+#else
+ options->gss_keyex = 0;
+#endif
if (options->gss_deleg_creds == -1)
options->gss_deleg_creds = 0;
if (options->password_authentication == -1)
diff -pur old/readconf.h new/readconf.h
--- old/readconf.h
+++ new/readconf.h
@@ -45,6 +45,7 @@ typedef struct {
int challenge_response_authentication;
/* Try S/Key or TIS, authentication. */
int gss_authentication; /* Try GSS authentication */
+ int gss_keyex; /* Try GSS key exchange */
int gss_deleg_creds; /* Delegate GSS credentials */
int password_authentication; /* Try password
* authentication. */
diff -pur old/servconf.c new/servconf.c
--- old/servconf.c
+++ new/servconf.c
@@ -117,6 +117,7 @@ initialize_server_options(ServerOptions
options->kerberos_ticket_cleanup = -1;
options->kerberos_get_afs_token = -1;
options->gss_authentication=-1;
+ options->gss_keyex = -1;
options->gss_cleanup_creds = -1;
options->gss_strict_acceptor = -1;
options->password_authentication = -1;
@@ -300,6 +301,12 @@ fill_default_server_options(ServerOption
#else
options->gss_authentication = 0;
#endif
+ if (options->gss_keyex == -1)
+#ifdef OPTION_DEFAULT_VALUE
+ options->gss_keyex = 1;
+#else
+ options->gss_keyex = 0;
+#endif
if (options->gss_cleanup_creds == -1)
options->gss_cleanup_creds = 1;
if (options->gss_strict_acceptor == -1)
@@ -442,6 +449,7 @@ typedef enum {
sHostbasedUsesNameFromPacketOnly, sHostbasedAcceptedKeyTypes,
sHostKeyAlgorithms,
sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile,
+ sGssKeyEx,
sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor,
sAcceptEnv, sPermitTunnel,
sMatch, sPermitOpen, sForceCommand, sChrootDirectory,
@@ -519,6 +527,8 @@ static struct {
#ifdef GSSAPI
{ "gssapiauthentication", sGssAuthentication, SSHCFG_ALL },
{ "gssauthentication", sGssAuthentication, SSHCFG_ALL }, /* alias */
+ { "gssapikeyexchange", sGssKeyEx, SSHCFG_ALL },
+ { "gsskeyex", sGssKeyEx, SSHCFG_ALL }, /* alias */
#ifdef USE_GSS_STORE_CRED
{ "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL },
#else /* USE_GSS_STORE_CRED */
@@ -528,6 +538,8 @@ static struct {
#else
{ "gssapiauthentication", sUnsupported, SSHCFG_ALL },
{ "gssauthentication", sUnsupported, SSHCFG_ALL }, /* alias */
+ { "gssapikeyexchange", sUnsupported,, SSHCFG_ALL },
+ { "gsskeyex", sUnsupported,, SSHCFG_ALL },
{ "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL },
{ "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL },
#endif
@@ -1311,6 +1323,10 @@ process_server_config_line(ServerOptions
intptr = &options->gss_authentication;
goto parse_flag;
+ case sGssKeyEx:
+ intptr = &options->gss_keyex;
+ goto parse_flag;
+
case sGssCleanupCreds:
intptr = &options->gss_cleanup_creds;
goto parse_flag;
@@ -2357,6 +2373,7 @@ dump_config(ServerOptions *o)
#endif
#ifdef GSSAPI
dump_cfg_fmtint(sGssAuthentication, o->gss_authentication);
+ dump_cfg_fmtint(sGssKeyEx, o->gss_keyex);
#ifndef USE_GSS_STORE_CRED
dump_cfg_fmtint(sGssCleanupCreds, o->gss_cleanup_creds);
#endif /* !USE_GSS_STORE_CRED */
diff -pur old/servconf.h new/servconf.h
--- old/servconf.h
+++ new/servconf.h
@@ -122,6 +122,7 @@ typedef struct {
int kerberos_get_afs_token; /* If true, try to get AFS token if
* authenticated with Kerberos. */
int gss_authentication; /* If true, permit GSSAPI authentication */
+ int gss_keyex; /* If true, permit GSSAPI key exchange */
int gss_cleanup_creds; /* If true, destroy cred cache on logout */
int gss_strict_acceptor; /* If true, restrict the GSSAPI acceptor name */
int password_authentication; /* If true, permit password
diff -pur old/ssh-gss.h new/ssh-gss.h
--- old/ssh-gss.h
+++ new/ssh-gss.h
@@ -61,6 +61,17 @@
#define SSH_GSS_OIDTYPE 0x06
+#define SSH2_MSG_KEXGSS_INIT 30
+#define SSH2_MSG_KEXGSS_CONTINUE 31
+#define SSH2_MSG_KEXGSS_COMPLETE 32
+#define SSH2_MSG_KEXGSS_HOSTKEY 33
+#define SSH2_MSG_KEXGSS_ERROR 34
+#define SSH2_MSG_KEXGSS_GROUPREQ 40
+#define SSH2_MSG_KEXGSS_GROUP 41
+#define KEX_GSS_GRP1_SHA1_ID "gss-group1-sha1-"
+#define KEX_GSS_GRP14_SHA1_ID "gss-group14-sha1-"
+#define KEX_GSS_GEX_SHA1_ID "gss-gex-sha1-"
+
typedef struct {
char *filename;
char *envvar;
@@ -98,6 +109,7 @@ typedef struct {
} Gssctxt;
extern ssh_gssapi_mech *supported_mechs[];
+extern Gssctxt *gss_kex_context;
int ssh_gssapi_check_oid(Gssctxt *, void *, size_t);
void ssh_gssapi_set_oid_data(Gssctxt *, void *, size_t);
@@ -122,6 +134,11 @@ void ssh_gssapi_buildmic(Buffer *, const
int ssh_gssapi_check_mechanism(Gssctxt **, gss_OID, const char *);
/* In the server */
+typedef int ssh_gssapi_check_fn(Gssctxt **, gss_OID, const char *);
+char *ssh_gssapi_client_mechanisms(const char *host);
+char *ssh_gssapi_kex_mechs(gss_OID_set, ssh_gssapi_check_fn *, const char *);
+gss_OID ssh_gssapi_id_kex(Gssctxt *, char *, int);
+int ssh_gssapi_server_check_mech(Gssctxt **,gss_OID, const char *);
OM_uint32 ssh_gssapi_server_ctx(Gssctxt **, gss_OID);
int ssh_gssapi_userok(char *name);
OM_uint32 ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t);
@@ -129,6 +146,8 @@ void ssh_gssapi_do_child(char ***, u_int
void ssh_gssapi_cleanup_creds(void);
void ssh_gssapi_storecreds(void);
+char *ssh_gssapi_server_mechanisms(void);
+int ssh_gssapi_oid_table_ok();
#endif /* GSSAPI */
#endif /* _SSH_GSS_H */
diff -pur old/ssh_config new/ssh_config
--- old/ssh_config
+++ new/ssh_config
@@ -26,6 +26,7 @@
# HostbasedAuthentication no
# GSSAPIAuthentication no
# GSSAPIDelegateCredentials no
+# GSSAPIKeyExchange yes
# BatchMode no
# CheckHostIP yes
# AddressFamily any
diff -pur old/ssh_config.5 new/ssh_config.5
--- old/ssh_config.5
+++ new/ssh_config.5
@@ -757,6 +757,12 @@ Specifies whether user authentication ba
The default on Solaris is
.Dq yes .
Note that this option applies to protocol version 2 only.
+.It Cm GSSAPIKeyExchange
+Specifies whether key exchange based on GSSAPI may be used. When using
+GSSAPI key exchange the server need not have a host key.
+The default on Solaris is
+.Dq yes .
+Note that this option applies to protocol version 2 only.
.It Cm GSSAPIDelegateCredentials
Forward (delegate) credentials to the server.
The default is
diff -pur old/sshconnect2.c new/sshconnect2.c
--- old/sshconnect2.c
+++ new/sshconnect2.c
@@ -163,12 +163,37 @@ ssh_kex2(char *host, struct sockaddr *ho
char *myproposal[PROPOSAL_MAX] = { KEX_CLIENT };
struct kex *kex;
int r;
+#ifdef GSSAPI
+ char *orig = NULL, *gss = NULL;
+ char *gss_host = NULL;
+#endif
+
xxx_host = host;
xxx_hostaddr = hostaddr;
+ if (options.kex_algorithms != NULL)
+ myproposal[PROPOSAL_KEX_ALGS] = options.kex_algorithms;
+
+#ifdef GSSAPI
+ if (options.gss_keyex) {
+ /* Add the GSSAPI mechanisms currently supported on this
+ * client to the key exchange algorithm proposal */
+ orig = myproposal[PROPOSAL_KEX_ALGS];
+
+ gss_host = (char *)get_canonical_hostname(1);
+
+ gss = ssh_gssapi_client_mechanisms(gss_host);
+ if (gss) {
+ debug("Offering GSSAPI proposal: %s", gss);
+ xasprintf(&myproposal[PROPOSAL_KEX_ALGS],
+ "%s,%s", gss, orig);
+ }
+ }
+#endif
+
myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal(
- options.kex_algorithms);
+ myproposal[PROPOSAL_KEX_ALGS]);
myproposal[PROPOSAL_ENC_ALGS_CTOS] =
compat_cipher_proposal(options.ciphers);
myproposal[PROPOSAL_ENC_ALGS_STOC] =
@@ -197,6 +222,17 @@ ssh_kex2(char *host, struct sockaddr *ho
order_hostkeyalgs(host, hostaddr, port));
}
+#ifdef GSSAPI
+ /* If we've got GSSAPI algorithms, then we also support the
+ * 'null' hostkey, as a last resort */
+ if (options.gss_keyex && gss) {
+ orig = myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS];
+ xasprintf(&myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS],
+ "%s,null", orig);
+ free(gss);
+ }
+#endif
+
if (options.rekey_limit || options.rekey_interval)
packet_set_rekey_limits((u_int32_t)options.rekey_limit,
(time_t)options.rekey_interval);
@@ -215,9 +251,22 @@ ssh_kex2(char *host, struct sockaddr *ho
# endif
#endif
kex->kex[KEX_C25519_SHA256] = kexc25519_client;
+#ifdef GSSAPI
+ if (options.gss_keyex) {
+ kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_client;
+ kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_client;
+ kex->kex[KEX_GSS_GEX_SHA1] = kexgss_client;
+ }
+#endif
kex->client_version_string=client_version_string;
kex->server_version_string=server_version_string;
kex->verify_host_key=&verify_host_key_callback;
+#ifdef GSSAPI
+ if (options.gss_keyex) {
+ kex->gss_deleg_creds = options.gss_deleg_creds;
+ kex->gss_host = gss_host;
+ }
+#endif
dispatch_run(DISPATCH_BLOCK, &kex->done, active_state);
@@ -310,6 +359,7 @@ int input_gssapi_token(int type, u_int32
int input_gssapi_hash(int type, u_int32_t, void *);
int input_gssapi_error(int, u_int32_t, void *);
int input_gssapi_errtok(int, u_int32_t, void *);
+int userauth_gsskeyex(Authctxt *authctxt);
#endif
void userauth(Authctxt *, char *);
@@ -325,6 +375,11 @@ static char *authmethods_get(void);
Authmethod authmethods[] = {
#ifdef GSSAPI
+ {"gssapi-keyex",
+ userauth_gsskeyex,
+ NULL,
+ &options.gss_authentication,
+ NULL},
{"gssapi-with-mic",
userauth_gssapi,
NULL,
@@ -649,7 +704,10 @@ userauth_gssapi(Authctxt *authctxt)
* once. */
if (gss_supported == NULL)
- gss_indicate_mechs(&min, &gss_supported);
+ if (GSS_ERROR(gss_indicate_mechs(&min, &gss_supported))) {
+ gss_supported = NULL;
+ return 0;
+ }
/* Check to see if the mechanism is usable before we offer it */
while (mech < gss_supported->count && !ok) {
@@ -753,8 +811,8 @@ input_gssapi_response(int type, u_int32_
{
Authctxt *authctxt = ctxt;
Gssctxt *gssctxt;
- int oidlen;
- char *oidv;
+ u_int oidlen;
+ u_char *oidv;
if (authctxt == NULL)
fatal("input_gssapi_response: no authentication context");
@@ -867,6 +925,48 @@ input_gssapi_error(int type, u_int32_t p
free(lang);
return 0;
}
+
+int
+userauth_gsskeyex(Authctxt *authctxt)
+{
+ Buffer b;
+ gss_buffer_desc gssbuf;
+ gss_buffer_desc mic = GSS_C_EMPTY_BUFFER;
+ OM_uint32 ms;
+
+ static int attempt = 0;
+ if (attempt++ >= 1)
+ return (0);
+
+ if (gss_kex_context == NULL) {
+ debug("No valid Key exchange context");
+ return (0);
+ }
+
+ ssh_gssapi_buildmic(&b, authctxt->server_user, authctxt->service,
+ "gssapi-keyex");
+
+ gssbuf.value = buffer_ptr(&b);
+ gssbuf.length = buffer_len(&b);
+
+ if (GSS_ERROR(ssh_gssapi_sign(gss_kex_context, &gssbuf, &mic))) {
+ buffer_free(&b);
+ return (0);
+ }
+
+ packet_start(SSH2_MSG_USERAUTH_REQUEST);
+ packet_put_cstring(authctxt->server_user);
+ packet_put_cstring(authctxt->service);
+ packet_put_cstring(authctxt->method->name);
+ packet_put_string(mic.value, mic.length);
+ packet_send();
+
+ buffer_free(&b);
+ gss_release_buffer(&ms, &mic);
+
+ return (1);
+}
+
#endif /* GSSAPI */
int
diff -pur old/sshd.c new/sshd.c
--- old/sshd.c
+++ new/sshd.c
@@ -1827,10 +1827,13 @@ main(int ac, char **av)
logit("Disabling protocol version 1. Could not load host key");
options.protocol &= ~SSH_PROTO_1;
}
+#ifndef GSSAPI
+ /* The GSSAPI key exchange can run without a host key */
if ((options.protocol & SSH_PROTO_2) && !sensitive_data.have_ssh2_key) {
logit("Disabling protocol version 2. Could not load host key");
options.protocol &= ~SSH_PROTO_2;
}
+#endif
if (!(options.protocol & (SSH_PROTO_1|SSH_PROTO_2))) {
logit("sshd: no hostkeys available -- exiting.");
exit(1);
@@ -2588,6 +2591,48 @@ do_ssh2_kex(void)
myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = compat_pkalg_proposal(
list_hostkey_types());
+#ifdef GSSAPI
+ {
+ char *orig;
+ char *gss = NULL;
+ char *newstr = NULL;
+ orig = myproposal[PROPOSAL_KEX_ALGS];
+
+ /*
+ * If we don't have a host key, then there's no point advertising
+ * the other key exchange algorithms
+ */
+
+ if (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]) == 0)
+ orig = NULL;
+
+ if (options.gss_keyex)
+ gss = ssh_gssapi_server_mechanisms();
+ else
+ gss = NULL;
+
+ if (gss && orig)
+ xasprintf(&newstr, "%s,%s", gss, orig);
+ else if (gss)
+ newstr = gss;
+ else if (orig)
+ newstr = orig;
+
+ /*
+ * If we've got GSSAPI mechanisms, then we've got the 'null' host
+ * key alg, but we can't tell people about it unless its the only
+ * host key algorithm we support
+ */
+ if (gss && (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS])) == 0)
+ myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = "null";
+
+ if (newstr)
+ myproposal[PROPOSAL_KEX_ALGS] = newstr;
+ else
+ fatal("No supported key exchange algorithms");
+ }
+#endif
+
/* start key exchange */
if ((r = kex_setup(active_state, myproposal)) != 0)
fatal("kex_setup: %s", ssh_err(r));
@@ -2602,6 +2647,13 @@ do_ssh2_kex(void)
# endif
#endif
kex->kex[KEX_C25519_SHA256] = kexc25519_server;
+#ifdef GSSAPI
+ if (options.gss_keyex) {
+ kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server;
+ kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_server;
+ kex->kex[KEX_GSS_GEX_SHA1] = kexgss_server;
+ }
+#endif
kex->server = 1;
kex->client_version_string=client_version_string;
kex->server_version_string=server_version_string;
diff -pur old/sshd_config new/sshd_config
--- old/sshd_config
+++ new/sshd_config
@@ -82,8 +82,9 @@ AuthorizedKeysFile .ssh/authorized_keys
#KerberosGetAFSToken no
# GSSAPI options
-#GSSAPIAuthentication no
+#GSSAPIAuthentication yes
#GSSAPICleanupCredentials yes
+#GSSAPIKeyExchange yes
# Set this to 'yes' to enable PAM authentication, account processing,
# and session processing. If this is enabled, PAM authentication will
diff -pur old/sshd_config.5 new/sshd_config.5
--- old/sshd_config.5
+++ new/sshd_config.5
@@ -621,6 +621,12 @@ Specifies whether user authentication ba
The default on Solaris is
.Dq yes .
Note that this option applies to protocol version 2 only.
+.It Cm GSSAPIKeyExchange
+Specifies whether key exchange based on GSSAPI is allowed. GSSAPI key exchange
+doesn't rely on ssh keys to verify host identity.
+The default on Solaris is
+.Dq yes .
+Note that this option applies to protocol version 2 only.
.It Cm GSSAPICleanupCredentials
Specifies whether to automatically destroy the user's credentials cache
on logout.
diff -pur old/sshkey.c new/sshkey.c
--- old/sshkey.c
+++ new/sshkey.c
@@ -112,6 +112,7 @@ static const struct keytype keytypes[] =
# endif /* OPENSSL_HAS_NISTP521 */
# endif /* OPENSSL_HAS_ECC */
#endif /* WITH_OPENSSL */
+ { "null", "null", KEY_NULL, 0, 0 },
{ NULL, NULL, -1, -1, 0 }
};
diff -pur old/sshkey.h new/sshkey.h
--- old/sshkey.h
+++ new/sshkey.h
@@ -62,6 +62,7 @@ enum sshkey_types {
KEY_DSA_CERT,
KEY_ECDSA_CERT,
KEY_ED25519_CERT,
+ KEY_NULL,
KEY_UNSPEC
};