Bugzilla – Attachment 1664 Details for
Bug 1242
GSSAPI Keyexchange support
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch to add GSSAPI Key Exchange support
gss-keyex (text/plain), 54.02 KB, created by
Simon Wilkinson
on 2009-07-27 00:03:05 AEST
(
hide
)
Description:
Patch to add GSSAPI Key Exchange support
Filename:
MIME Type:
Creator:
Simon Wilkinson
Created:
2009-07-27 00:03:05 AEST
Size:
54.02 KB
patch
obsolete
>Index: Makefile.in >=================================================================== >--- Makefile.in.orig 2009-07-26 14:46:23.000000000 +0100 >+++ Makefile.in 2009-07-26 14:46:30.000000000 +0100 >@@ -71,7 +71,8 @@ > atomicio.o key.o dispatch.o kex.o mac.o uidswap.o uuencode.o misc.o \ > monitor_fdpass.o rijndael.o ssh-dss.o ssh-rsa.o dh.o kexdh.o \ > kexgex.o kexdhc.o kexgexc.o scard.o msg.o progressmeter.o dns.o \ >- entropy.o scard-opensc.o gss-genr.o umac.o jpake.o schnorr.o >+ entropy.o scard-opensc.o gss-genr.o umac.o jpake.o schnorr.o \ >+ kexgssc.o > > SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \ > sshconnect.o sshconnect1.o sshconnect2.o mux.o >@@ -84,7 +85,7 @@ > auth2-none.o auth2-passwd.o auth2-pubkey.o auth2-jpake.o \ > monitor_mm.o monitor.o monitor_wrap.o kexdhs.o kexgexs.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 \ > audit.o audit-bsm.o platform.o sftp-server.o sftp-common.o > >Index: auth2-gss.c >=================================================================== >--- auth2-gss.c.orig 2009-07-26 14:46:23.000000000 +0100 >+++ auth2-gss.c 2009-07-26 14:47:54.000000000 +0100 >@@ -1,7 +1,7 @@ > /* $OpenBSD: auth2-gss.c,v 1.16 2007/10/29 00:52:45 dtucker 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 >@@ -52,6 +52,39 @@ > static void input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt); > static void 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); >+ xfree(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) >@@ -279,7 +312,8 @@ > gssbuf.length = buffer_len(&b); > > if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gssctxt, &gssbuf, &mic)))) >- authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user)); >+ authenticated = >+ PRIVSEP(ssh_gssapi_userok(authctxt->user)); > else > logit("GSSAPI MIC check failed"); > >@@ -294,6 +328,12 @@ > userauth_finish(authctxt, authenticated, "gssapi-with-mic"); > } > >+Authmethod method_gsskeyex = { >+ "gssapi-keyex", >+ userauth_gsskeyex, >+ &options.gss_authentication >+}; >+ > Authmethod method_gssapi = { > "gssapi-with-mic", > userauth_gssapi, >Index: auth2.c >=================================================================== >--- auth2.c.orig 2009-07-26 14:46:23.000000000 +0100 >+++ auth2.c 2009-07-26 14:46:30.000000000 +0100 >@@ -69,6 +69,7 @@ > extern Authmethod method_kbdint; > extern Authmethod method_hostbased; > #ifdef GSSAPI >+extern Authmethod method_gsskeyex; > extern Authmethod method_gssapi; > #endif > #ifdef JPAKE >@@ -79,6 +80,7 @@ > &method_none, > &method_pubkey, > #ifdef GSSAPI >+ &method_gsskeyex, > &method_gssapi, > #endif > #ifdef JPAKE >Index: gss-genr.c >=================================================================== >--- gss-genr.c.orig 2009-07-26 14:46:23.000000000 +0100 >+++ gss-genr.c 2009-07-26 14:49:32.000000000 +0100 >@@ -1,7 +1,7 @@ > /* $OpenBSD: gss-genr.c,v 1.19 2007/06/12 11:56:15 dtucker 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 >@@ -39,12 +39,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++) >+ xfree(gss_enc2oid[i].encoded); >+ xfree(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) { >+ xfree(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) >@@ -229,6 +384,9 @@ > 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); >@@ -236,6 +394,19 @@ > 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) >@@ -254,6 +425,10 @@ > 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 && >@@ -272,7 +447,7 @@ > GSS_C_NO_BUFFER); > } > >- if (GSS_ERROR(major)) >+ if (GSS_ERROR(major) || intctx != NULL) > ssh_gssapi_delete_ctx(ctx); > > return (!GSS_ERROR(major)); >Index: gss-serv.c >=================================================================== >--- gss-serv.c.orig 2009-07-26 14:46:23.000000000 +0100 >+++ gss-serv.c 2009-07-26 14:49:32.000000000 +0100 >@@ -1,7 +1,7 @@ > /* $OpenBSD: gss-serv.c,v 1.22 2008/05/08 12:02:23 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 >@@ -48,6 +48,7 @@ > #include "servconf.h" > > #include "ssh-gss.h" >+#include "monitor_wrap.h" > > extern ServerOptions options; > >@@ -124,6 +125,28 @@ > } > > /* 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) > { >@@ -133,7 +156,9 @@ > 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, >@@ -362,14 +387,4 @@ > 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 >Index: kex.c >=================================================================== >--- kex.c.orig 2009-07-26 14:46:23.000000000 +0100 >+++ kex.c 2009-07-26 14:46:30.000000000 +0100 >@@ -49,6 +49,10 @@ > #include "dispatch.h" > #include "monitor.h" > >+#ifdef GSSAPI >+#include "ssh-gss.h" >+#endif >+ > #define KEX_COOKIE_LEN 16 > > #if OPENSSL_VERSION_NUMBER >= 0x00907000L >@@ -327,6 +331,20 @@ > k->kex_type = KEX_DH_GEX_SHA256; > k->evp_md = evp_ssh_sha256(); > #endif >+#ifdef GSSAPI >+ } else if (strncmp(k->name, KEX_GSS_GEX_SHA1_ID, >+ sizeof(KEX_GSS_GEX_SHA1_ID) - 1) == 0) { >+ k->kex_type = KEX_GSS_GEX_SHA1; >+ k->evp_md = EVP_sha1(); >+ } else if (strncmp(k->name, KEX_GSS_GRP1_SHA1_ID, >+ sizeof(KEX_GSS_GRP1_SHA1_ID) - 1) == 0) { >+ k->kex_type = KEX_GSS_GRP1_SHA1; >+ k->evp_md = EVP_sha1(); >+ } else if (strncmp(k->name, KEX_GSS_GRP14_SHA1_ID, >+ sizeof(KEX_GSS_GRP14_SHA1_ID) - 1) == 0) { >+ k->kex_type = KEX_GSS_GRP14_SHA1; >+ k->evp_md = EVP_sha1(); >+#endif > } else > fatal("bad kex alg %s", k->name); > } >Index: kex.h >=================================================================== >--- kex.h.orig 2009-07-26 14:46:23.000000000 +0100 >+++ kex.h 2009-07-26 14:49:32.000000000 +0100 >@@ -64,6 +64,9 @@ > KEX_DH_GRP14_SHA1, > KEX_DH_GEX_SHA1, > KEX_DH_GEX_SHA256, >+ KEX_GSS_GRP1_SHA1, >+ KEX_GSS_GRP14_SHA1, >+ KEX_GSS_GEX_SHA1, > KEX_MAX > }; > >@@ -119,6 +122,11 @@ > sig_atomic_t done; > int flags; > const EVP_MD *evp_md; >+#ifdef GSSAPI >+ int gss_deleg_creds; >+ int gss_trust_dns; >+ char *gss_host; >+#endif > char *client_version_string; > char *server_version_string; > int (*verify_host_key)(Key *); >@@ -141,6 +149,11 @@ > void kexgex_client(Kex *); > void kexgex_server(Kex *); > >+#ifdef GSSAPI >+void kexgss_client(Kex *); >+void kexgss_server(Kex *); >+#endif >+ > void > kex_dh_hash(char *, char *, char *, int, char *, int, u_char *, int, > BIGNUM *, BIGNUM *, BIGNUM *, u_char **, u_int *); >Index: kexgssc.c >=================================================================== >--- /dev/null 1970-01-01 00:00:00.000000000 +0000 >+++ kexgssc.c 2009-07-26 14:49:32.000000000 +0100 >@@ -0,0 +1,327 @@ >+/* >+ * 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 >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR >+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES >+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. >+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, >+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT >+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, >+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY >+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT >+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF >+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#include "includes.h" >+ >+#ifdef GSSAPI >+ >+#include "includes.h" >+ >+#include <openssl/crypto.h> >+#include <openssl/bn.h> >+ >+#include <string.h> >+ >+#include "xmalloc.h" >+#include "buffer.h" >+#include "ssh2.h" >+#include "key.h" >+#include "cipher.h" >+#include "kex.h" >+#include "log.h" >+#include "packet.h" >+#include "dh.h" >+ >+#include "ssh-gss.h" >+ >+void >+kexgss_client(Kex *kex) { >+ gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; >+ gss_buffer_desc recv_tok, gssbuf, msg_tok, *token_ptr; >+ Gssctxt *ctxt; >+ OM_uint32 maj_status, min_status, ret_flags; >+ u_int klen, kout, slen = 0, hashlen, strlen; >+ DH *dh; >+ BIGNUM *dh_server_pub = NULL; >+ BIGNUM *shared_secret = NULL; >+ BIGNUM *p = NULL; >+ BIGNUM *g = NULL; >+ u_char *kbuf, *hash; >+ u_char *serverhostkey = NULL; >+ u_char *empty = ""; >+ char *msg; >+ char *lang; >+ int type = 0; >+ int first = 1; >+ int nbits = 0, min = DH_GRP_MIN, max = DH_GRP_MAX; >+ >+ /* Initialise our GSSAPI world */ >+ ssh_gssapi_build_ctx(&ctxt); >+ if (ssh_gssapi_id_kex(ctxt, kex->name, kex->kex_type) >+ == GSS_C_NO_OID) >+ fatal("Couldn't identify host exchange"); >+ >+ if (ssh_gssapi_import_name(ctxt, kex->gss_host)) >+ fatal("Couldn't import hostname"); >+ >+ switch (kex->kex_type) { >+ case KEX_GSS_GRP1_SHA1: >+ dh = dh_new_group1(); >+ break; >+ case KEX_GSS_GRP14_SHA1: >+ dh = dh_new_group14(); >+ break; >+ case KEX_GSS_GEX_SHA1: >+ debug("Doing group exchange\n"); >+ nbits = dh_estimate(kex->we_need * 8); >+ packet_start(SSH2_MSG_KEXGSS_GROUPREQ); >+ packet_put_int(min); >+ packet_put_int(nbits); >+ packet_put_int(max); >+ >+ packet_send(); >+ >+ packet_read_expect(SSH2_MSG_KEXGSS_GROUP); >+ >+ if ((p = BN_new()) == NULL) >+ fatal("BN_new() failed"); >+ packet_get_bignum2(p); >+ if ((g = BN_new()) == NULL) >+ fatal("BN_new() failed"); >+ packet_get_bignum2(g); >+ packet_check_eom(); >+ >+ if (BN_num_bits(p) < min || BN_num_bits(p) > max) >+ fatal("GSSGRP_GEX group out of range: %d !< %d !< %d", >+ min, BN_num_bits(p), max); >+ >+ dh = dh_new_group(g, p); >+ break; >+ default: >+ fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type); >+ } >+ >+ /* Step 1 - e is dh->pub_key */ >+ dh_gen_key(dh, kex->we_need * 8); >+ >+ /* This is f, we initialise it now to make life easier */ >+ dh_server_pub = BN_new(); >+ if (dh_server_pub == NULL) >+ fatal("dh_server_pub == NULL"); >+ >+ token_ptr = GSS_C_NO_BUFFER; >+ >+ do { >+ debug("Calling gss_init_sec_context"); >+ >+ maj_status = ssh_gssapi_init_ctx(ctxt, >+ kex->gss_deleg_creds, token_ptr, &send_tok, >+ &ret_flags); >+ >+ if (GSS_ERROR(maj_status)) { >+ if (send_tok.length != 0) { >+ packet_start(SSH2_MSG_KEXGSS_CONTINUE); >+ packet_put_string(send_tok.value, >+ send_tok.length); >+ } >+ fatal("gss_init_context failed"); >+ } >+ >+ /* If we've got an old receive buffer get rid of it */ >+ if (token_ptr != GSS_C_NO_BUFFER) >+ xfree(recv_tok.value); >+ >+ if (maj_status == GSS_S_COMPLETE) { >+ /* If mutual state flag is not true, kex fails */ >+ if (!(ret_flags & GSS_C_MUTUAL_FLAG)) >+ fatal("Mutual authentication failed"); >+ >+ /* If integ avail flag is not true kex fails */ >+ if (!(ret_flags & GSS_C_INTEG_FLAG)) >+ fatal("Integrity check failed"); >+ } >+ >+ /* >+ * If we have data to send, then the last message that we >+ * received cannot have been a 'complete'. >+ */ >+ if (send_tok.length != 0) { >+ if (first) { >+ packet_start(SSH2_MSG_KEXGSS_INIT); >+ packet_put_string(send_tok.value, >+ send_tok.length); >+ packet_put_bignum2(dh->pub_key); >+ first = 0; >+ } else { >+ packet_start(SSH2_MSG_KEXGSS_CONTINUE); >+ packet_put_string(send_tok.value, >+ send_tok.length); >+ } >+ packet_send(); >+ gss_release_buffer(&min_status, &send_tok); >+ >+ /* If we've sent them data, they should reply */ >+ do { >+ type = packet_read(); >+ if (type == SSH2_MSG_KEXGSS_HOSTKEY) { >+ debug("Received KEXGSS_HOSTKEY"); >+ if (serverhostkey) >+ fatal("Server host key received more than once"); >+ serverhostkey = >+ packet_get_string(&slen); >+ } >+ } while (type == SSH2_MSG_KEXGSS_HOSTKEY); >+ >+ switch (type) { >+ case SSH2_MSG_KEXGSS_CONTINUE: >+ debug("Received GSSAPI_CONTINUE"); >+ if (maj_status == GSS_S_COMPLETE) >+ fatal("GSSAPI Continue received from server when complete"); >+ recv_tok.value = packet_get_string(&strlen); >+ recv_tok.length = strlen; >+ break; >+ case SSH2_MSG_KEXGSS_COMPLETE: >+ debug("Received GSSAPI_COMPLETE"); >+ packet_get_bignum2(dh_server_pub); >+ msg_tok.value = packet_get_string(&strlen); >+ msg_tok.length = strlen; >+ >+ /* Is there a token included? */ >+ if (packet_get_char()) { >+ recv_tok.value= >+ packet_get_string(&strlen); >+ recv_tok.length = strlen; >+ /* If we're already complete - protocol error */ >+ if (maj_status == GSS_S_COMPLETE) >+ packet_disconnect("Protocol error: received token when complete"); >+ } else { >+ /* No token included */ >+ if (maj_status != GSS_S_COMPLETE) >+ packet_disconnect("Protocol error: did not receive final token"); >+ } >+ break; >+ case SSH2_MSG_KEXGSS_ERROR: >+ debug("Received Error"); >+ maj_status = packet_get_int(); >+ min_status = packet_get_int(); >+ msg = packet_get_string(NULL); >+ lang = packet_get_string(NULL); >+ fatal("GSSAPI Error: \n%.400s",msg); >+ default: >+ packet_disconnect("Protocol error: didn't expect packet type %d", >+ type); >+ } >+ token_ptr = &recv_tok; >+ } else { >+ /* No data, and not complete */ >+ if (maj_status != GSS_S_COMPLETE) >+ fatal("Not complete, and no token output"); >+ } >+ } while (maj_status & GSS_S_CONTINUE_NEEDED); >+ >+ /* >+ * We _must_ have received a COMPLETE message in reply from the >+ * server, which will have set dh_server_pub and msg_tok >+ */ >+ >+ if (type != SSH2_MSG_KEXGSS_COMPLETE) >+ fatal("Didn't receive a SSH2_MSG_KEXGSS_COMPLETE when I expected it"); >+ >+ /* Check f in range [1, p-1] */ >+ if (!dh_pub_is_valid(dh, dh_server_pub)) >+ packet_disconnect("bad server public DH value"); >+ >+ /* compute K=f^x mod p */ >+ klen = DH_size(dh); >+ kbuf = xmalloc(klen); >+ kout = DH_compute_key(kbuf, dh_server_pub, dh); >+ if (kout < 0) >+ fatal("DH_compute_key: failed"); >+ >+ shared_secret = BN_new(); >+ if (shared_secret == NULL) >+ fatal("kexgss_client: BN_new failed"); >+ >+ if (BN_bin2bn(kbuf, kout, shared_secret) == NULL) >+ fatal("kexdh_client: BN_bin2bn failed"); >+ >+ memset(kbuf, 0, klen); >+ xfree(kbuf); >+ >+ switch (kex->kex_type) { >+ case KEX_GSS_GRP1_SHA1: >+ case KEX_GSS_GRP14_SHA1: >+ kex_dh_hash( kex->client_version_string, >+ kex->server_version_string, >+ buffer_ptr(&kex->my), buffer_len(&kex->my), >+ buffer_ptr(&kex->peer), buffer_len(&kex->peer), >+ (serverhostkey ? serverhostkey : empty), slen, >+ dh->pub_key, /* e */ >+ dh_server_pub, /* f */ >+ shared_secret, /* K */ >+ &hash, &hashlen >+ ); >+ break; >+ case KEX_GSS_GEX_SHA1: >+ kexgex_hash( >+ kex->evp_md, >+ kex->client_version_string, >+ kex->server_version_string, >+ buffer_ptr(&kex->my), buffer_len(&kex->my), >+ buffer_ptr(&kex->peer), buffer_len(&kex->peer), >+ (serverhostkey ? serverhostkey : empty), slen, >+ min, nbits, max, >+ dh->p, dh->g, >+ dh->pub_key, >+ dh_server_pub, >+ shared_secret, >+ &hash, &hashlen >+ ); >+ break; >+ default: >+ fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type); >+ } >+ >+ gssbuf.value = hash; >+ gssbuf.length = hashlen; >+ >+ /* Verify that the hash matches the MIC we just got. */ >+ if (GSS_ERROR(ssh_gssapi_checkmic(ctxt, &gssbuf, &msg_tok))) >+ packet_disconnect("Hash's MIC didn't verify"); >+ >+ xfree(msg_tok.value); >+ >+ DH_free(dh); >+ if (serverhostkey) >+ xfree(serverhostkey); >+ BN_clear_free(dh_server_pub); >+ >+ /* save session id */ >+ if (kex->session_id == NULL) { >+ kex->session_id_len = hashlen; >+ kex->session_id = xmalloc(kex->session_id_len); >+ memcpy(kex->session_id, hash, kex->session_id_len); >+ } >+ >+ if (gss_kex_context == NULL) >+ gss_kex_context = ctxt; >+ else >+ ssh_gssapi_delete_ctx(&ctxt); >+ >+ kex_derive_keys(kex, hash, hashlen, shared_secret); >+ BN_clear_free(shared_secret); >+ kex_finish(kex); >+} >+ >+#endif /* GSSAPI */ >Index: kexgsss.c >=================================================================== >--- /dev/null 1970-01-01 00:00:00.000000000 +0000 >+++ kexgsss.c 2009-07-26 14:46:30.000000000 +0100 >@@ -0,0 +1,280 @@ >+/* >+ * 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 >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR >+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES >+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. >+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, >+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT >+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, >+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY >+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT >+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF >+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#include "includes.h" >+ >+#ifdef GSSAPI >+ >+#include <string.h> >+ >+#include <openssl/crypto.h> >+#include <openssl/bn.h> >+ >+#include "xmalloc.h" >+#include "buffer.h" >+#include "ssh2.h" >+#include "key.h" >+#include "cipher.h" >+#include "kex.h" >+#include "log.h" >+#include "packet.h" >+#include "dh.h" >+#include "ssh-gss.h" >+#include "monitor_wrap.h" >+ >+void >+kexgss_server(Kex *kex) >+{ >+ OM_uint32 maj_status, min_status; >+ >+ /* >+ * Some GSSAPI implementations use the input value of ret_flags (an >+ * output variable) as a means of triggering mechanism specific >+ * features. Initializing it to zero avoids inadvertently >+ * activating this non-standard behaviour. >+ */ >+ >+ OM_uint32 ret_flags = 0; >+ gss_buffer_desc gssbuf, recv_tok, msg_tok; >+ gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; >+ Gssctxt *ctxt = NULL; >+ u_int slen, klen, kout, hashlen; >+ u_char *kbuf, *hash; >+ DH *dh; >+ int min = -1, max = -1, nbits = -1; >+ BIGNUM *shared_secret = NULL; >+ BIGNUM *dh_client_pub = NULL; >+ int type = 0; >+ gss_OID oid; >+ char *mechs; >+ >+ /* Initialise GSSAPI */ >+ >+ /* If we're rekeying, privsep means that some of the private structures >+ * in the GSSAPI code are no longer available. This kludges them back >+ * into life >+ */ >+ if (!ssh_gssapi_oid_table_ok()) >+ if ((mechs = ssh_gssapi_server_mechanisms())) >+ xfree(mechs); >+ >+ debug2("%s: Identifying %s", __func__, kex->name); >+ oid = ssh_gssapi_id_kex(NULL, kex->name, kex->kex_type); >+ if (oid == GSS_C_NO_OID) >+ fatal("Unknown gssapi mechanism"); >+ >+ debug2("%s: Acquiring credentials", __func__); >+ >+ if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, oid)))) >+ fatal("Unable to acquire credentials for the server"); >+ >+ switch (kex->kex_type) { >+ case KEX_GSS_GRP1_SHA1: >+ dh = dh_new_group1(); >+ break; >+ case KEX_GSS_GRP14_SHA1: >+ dh = dh_new_group14(); >+ break; >+ case KEX_GSS_GEX_SHA1: >+ debug("Doing group exchange"); >+ packet_read_expect(SSH2_MSG_KEXGSS_GROUPREQ); >+ min = packet_get_int(); >+ nbits = packet_get_int(); >+ max = packet_get_int(); >+ min = MAX(DH_GRP_MIN, min); >+ max = MIN(DH_GRP_MAX, max); >+ packet_check_eom(); >+ if (max < min || nbits < min || max < nbits) >+ fatal("GSS_GEX, bad parameters: %d !< %d !< %d", >+ min, nbits, max); >+ dh = PRIVSEP(choose_dh(min, nbits, max)); >+ if (dh == NULL) >+ packet_disconnect("Protocol error: no matching group found"); >+ >+ packet_start(SSH2_MSG_KEXGSS_GROUP); >+ packet_put_bignum2(dh->p); >+ packet_put_bignum2(dh->g); >+ packet_send(); >+ >+ packet_write_wait(); >+ break; >+ default: >+ fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type); >+ } >+ >+ dh_gen_key(dh, kex->we_need * 8); >+ >+ do { >+ debug("Wait SSH2_MSG_GSSAPI_INIT"); >+ type = packet_read(); >+ switch(type) { >+ case SSH2_MSG_KEXGSS_INIT: >+ if (dh_client_pub != NULL) >+ fatal("Received KEXGSS_INIT after initialising"); >+ recv_tok.value = packet_get_string(&slen); >+ recv_tok.length = slen; >+ >+ if ((dh_client_pub = BN_new()) == NULL) >+ fatal("dh_client_pub == NULL"); >+ >+ packet_get_bignum2(dh_client_pub); >+ >+ /* Send SSH_MSG_KEXGSS_HOSTKEY here, if we want */ >+ break; >+ case SSH2_MSG_KEXGSS_CONTINUE: >+ recv_tok.value = packet_get_string(&slen); >+ recv_tok.length = slen; >+ break; >+ default: >+ packet_disconnect( >+ "Protocol error: didn't expect packet type %d", >+ type); >+ } >+ >+ maj_status = PRIVSEP(ssh_gssapi_accept_ctx(ctxt, &recv_tok, >+ &send_tok, &ret_flags)); >+ >+ xfree(recv_tok.value); >+ >+ if (maj_status != GSS_S_COMPLETE && send_tok.length == 0) >+ fatal("Zero length token output when incomplete"); >+ >+ if (dh_client_pub == NULL) >+ fatal("No client public key"); >+ >+ if (maj_status & GSS_S_CONTINUE_NEEDED) { >+ debug("Sending GSSAPI_CONTINUE"); >+ packet_start(SSH2_MSG_KEXGSS_CONTINUE); >+ packet_put_string(send_tok.value, send_tok.length); >+ packet_send(); >+ gss_release_buffer(&min_status, &send_tok); >+ } >+ } while (maj_status & GSS_S_CONTINUE_NEEDED); >+ >+ if (GSS_ERROR(maj_status)) { >+ if (send_tok.length > 0) { >+ packet_start(SSH2_MSG_KEXGSS_CONTINUE); >+ packet_put_string(send_tok.value, send_tok.length); >+ packet_send(); >+ } >+ fatal("accept_ctx died"); >+ } >+ >+ if (!(ret_flags & GSS_C_MUTUAL_FLAG)) >+ fatal("Mutual Authentication flag wasn't set"); >+ >+ if (!(ret_flags & GSS_C_INTEG_FLAG)) >+ fatal("Integrity flag wasn't set"); >+ >+ if (!dh_pub_is_valid(dh, dh_client_pub)) >+ packet_disconnect("bad client public DH value"); >+ >+ klen = DH_size(dh); >+ kbuf = xmalloc(klen); >+ kout = DH_compute_key(kbuf, dh_client_pub, dh); >+ if (kout < 0) >+ fatal("DH_compute_key: failed"); >+ >+ shared_secret = BN_new(); >+ if (shared_secret == NULL) >+ fatal("kexgss_server: BN_new failed"); >+ >+ if (BN_bin2bn(kbuf, kout, shared_secret) == NULL) >+ fatal("kexgss_server: BN_bin2bn failed"); >+ >+ memset(kbuf, 0, klen); >+ xfree(kbuf); >+ >+ switch (kex->kex_type) { >+ case KEX_GSS_GRP1_SHA1: >+ case KEX_GSS_GRP14_SHA1: >+ kex_dh_hash( >+ kex->client_version_string, kex->server_version_string, >+ buffer_ptr(&kex->peer), buffer_len(&kex->peer), >+ buffer_ptr(&kex->my), buffer_len(&kex->my), >+ NULL, 0, /* Change this if we start sending host keys */ >+ dh_client_pub, dh->pub_key, shared_secret, >+ &hash, &hashlen >+ ); >+ break; >+ case KEX_GSS_GEX_SHA1: >+ kexgex_hash( >+ kex->evp_md, >+ kex->client_version_string, kex->server_version_string, >+ buffer_ptr(&kex->peer), buffer_len(&kex->peer), >+ buffer_ptr(&kex->my), buffer_len(&kex->my), >+ NULL, 0, >+ min, nbits, max, >+ dh->p, dh->g, >+ dh_client_pub, >+ dh->pub_key, >+ shared_secret, >+ &hash, &hashlen >+ ); >+ break; >+ default: >+ fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type); >+ } >+ >+ BN_clear_free(dh_client_pub); >+ >+ if (kex->session_id == NULL) { >+ kex->session_id_len = hashlen; >+ kex->session_id = xmalloc(kex->session_id_len); >+ memcpy(kex->session_id, hash, kex->session_id_len); >+ } >+ >+ gssbuf.value = hash; >+ gssbuf.length = hashlen; >+ >+ if (GSS_ERROR(PRIVSEP(ssh_gssapi_sign(ctxt,&gssbuf,&msg_tok)))) >+ fatal("Couldn't get MIC"); >+ >+ packet_start(SSH2_MSG_KEXGSS_COMPLETE); >+ packet_put_bignum2(dh->pub_key); >+ packet_put_string(msg_tok.value,msg_tok.length); >+ >+ if (send_tok.length != 0) { >+ packet_put_char(1); /* true */ >+ packet_put_string(send_tok.value, send_tok.length); >+ } else { >+ packet_put_char(0); /* false */ >+ } >+ packet_send(); >+ >+ gss_release_buffer(&min_status, &send_tok); >+ gss_release_buffer(&min_status, &msg_tok); >+ >+ if (gss_kex_context == NULL) >+ gss_kex_context = ctxt; >+ else >+ ssh_gssapi_delete_ctx(&ctxt); >+ >+ DH_free(dh); >+ >+ kex_derive_keys(kex, hash, hashlen, shared_secret); >+ BN_clear_free(shared_secret); >+ kex_finish(kex); >+} >+#endif /* GSSAPI */ >Index: key.c >=================================================================== >--- key.c.orig 2009-07-26 14:46:23.000000000 +0100 >+++ key.c 2009-07-26 14:46:30.000000000 +0100 >@@ -764,6 +764,8 @@ > return KEY_RSA; > } else if (strcmp(name, "ssh-dss") == 0) { > return KEY_DSA; >+ } else if (strcmp(name, "null") == 0) { >+ return KEY_NULL; > } > debug2("key_type_from_name: unknown key type '%s'", name); > return KEY_UNSPEC; >Index: key.h >=================================================================== >--- key.h.orig 2009-07-26 14:46:23.000000000 +0100 >+++ key.h 2009-07-26 14:46:30.000000000 +0100 >@@ -34,6 +34,7 @@ > KEY_RSA1, > KEY_RSA, > KEY_DSA, >+ KEY_NULL, > KEY_UNSPEC > }; > enum fp_type { >Index: monitor.c >=================================================================== >--- monitor.c.orig 2009-07-26 14:46:23.000000000 +0100 >+++ monitor.c 2009-07-26 14:46:30.000000000 +0100 >@@ -170,6 +170,7 @@ > 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 >@@ -239,6 +240,7 @@ > {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 > #ifdef JPAKE > {MONITOR_REQ_JPAKE_GET_PWDATA, MON_ONCE, mm_answer_jpake_get_pwdata}, >@@ -251,6 +253,11 @@ > }; > > 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 > {MONITOR_REQ_MODULI, 0, mm_answer_moduli}, > {MONITOR_REQ_SIGN, 0, mm_answer_sign}, > {MONITOR_REQ_PTY, 0, mm_answer_pty}, >@@ -355,6 +362,10 @@ > /* 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; > >@@ -441,6 +452,10 @@ > 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); >@@ -1699,6 +1714,13 @@ > kex->kex[KEX_DH_GRP14_SHA1] = kexdh_server; > kex->kex[KEX_DH_GEX_SHA1] = kexgex_server; > kex->kex[KEX_DH_GEX_SHA256] = kexgex_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->hostkey_type = buffer_get_int(m); > kex->kex_type = buffer_get_int(m); >@@ -1898,6 +1920,9 @@ > 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; > >@@ -1925,6 +1950,9 @@ > 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); >@@ -1942,6 +1970,7 @@ > 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); > } >@@ -1953,6 +1982,9 @@ > 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); >@@ -1979,6 +2011,9 @@ > { > 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); >@@ -1992,6 +2027,48 @@ > /* 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); >+ >+ xfree(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 */ > > #ifdef JPAKE >Index: monitor.h >=================================================================== >--- monitor.h.orig 2009-07-26 14:46:23.000000000 +0100 >+++ monitor.h 2009-07-26 14:46:30.000000000 +0100 >@@ -53,6 +53,7 @@ > MONITOR_REQ_GSSSTEP, MONITOR_ANS_GSSSTEP, > MONITOR_REQ_GSSUSEROK, MONITOR_ANS_GSSUSEROK, > MONITOR_REQ_GSSCHECKMIC, MONITOR_ANS_GSSCHECKMIC, >+ MONITOR_REQ_GSSSIGN, MONITOR_ANS_GSSSIGN, > MONITOR_REQ_PAM_START, > MONITOR_REQ_PAM_ACCOUNT, MONITOR_ANS_PAM_ACCOUNT, > MONITOR_REQ_PAM_INIT_CTX, MONITOR_ANS_PAM_INIT_CTX, >Index: monitor_wrap.c >=================================================================== >--- monitor_wrap.c.orig 2009-07-26 14:46:23.000000000 +0100 >+++ monitor_wrap.c 2009-07-26 14:46:30.000000000 +0100 >@@ -1256,6 +1256,29 @@ > 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 */ > > #ifdef JPAKE >Index: monitor_wrap.h >=================================================================== >--- monitor_wrap.h.orig 2009-07-26 14:46:23.000000000 +0100 >+++ monitor_wrap.h 2009-07-26 14:46:30.000000000 +0100 >@@ -59,6 +59,7 @@ > 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 >Index: readconf.c >=================================================================== >--- readconf.c.orig 2009-07-26 14:46:23.000000000 +0100 >+++ readconf.c 2009-07-26 14:49:32.000000000 +0100 >@@ -127,7 +127,7 @@ > oClearAllForwardings, oNoHostAuthenticationForLocalhost, > oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout, > oAddressFamily, oGssAuthentication, oGssDelegateCreds, >- oGssTrustDns, >+ oGssTrustDns, oGssKeyEx, > oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly, > oSendEnv, oControlPath, oControlMaster, oHashKnownHosts, > oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand, >@@ -165,10 +165,12 @@ > { "afstokenpassing", oUnsupported }, > #if defined(GSSAPI) > { "gssapiauthentication", oGssAuthentication }, >+ { "gssapikeyexchange", oGssKeyEx }, > { "gssapidelegatecredentials", oGssDelegateCreds }, > { "gssapitrustdns", oGssTrustDns }, > #else > { "gssapiauthentication", oUnsupported }, >+ { "gssapikeyexchange", oUnsupported }, > { "gssapidelegatecredentials", oUnsupported }, > { "gssapitrustdns", oUnsupported }, > #endif >@@ -456,6 +458,10 @@ > 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; >@@ -1015,6 +1021,7 @@ > options->pubkey_authentication = -1; > options->challenge_response_authentication = -1; > options->gss_authentication = -1; >+ options->gss_keyex = -1; > options->gss_deleg_creds = -1; > options->gss_trust_dns = -1; > options->password_authentication = -1; >@@ -1107,6 +1114,8 @@ > options->challenge_response_authentication = 1; > if (options->gss_authentication == -1) > options->gss_authentication = 0; >+ if (options->gss_keyex == -1) >+ options->gss_keyex = 0; > if (options->gss_deleg_creds == -1) > options->gss_deleg_creds = 0; > if (options->gss_trust_dns == -1) >Index: readconf.h >=================================================================== >--- readconf.h.orig 2009-07-26 14:46:23.000000000 +0100 >+++ readconf.h 2009-07-26 14:49:32.000000000 +0100 >@@ -44,6 +44,7 @@ > 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 gss_trust_dns; /* Trust DNS for GSS canonicalization */ > int password_authentication; /* Try password >Index: servconf.c >=================================================================== >--- servconf.c.orig 2009-07-26 14:46:23.000000000 +0100 >+++ servconf.c 2009-07-26 14:46:30.000000000 +0100 >@@ -92,6 +92,7 @@ > 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; >@@ -211,10 +212,12 @@ > options->kerberos_get_afs_token = 0; > if (options->gss_authentication == -1) > options->gss_authentication = 0; >+ if (options->gss_keyex == -1) >+ options->gss_keyex = 0; > if (options->gss_cleanup_creds == -1) > options->gss_cleanup_creds = 1; > if (options->gss_strict_acceptor == -1) >- options->gss_strict_acceptor = 0; >+ options->gss_strict_acceptor = 1; > if (options->password_authentication == -1) > options->password_authentication = 1; > if (options->kbd_interactive_authentication == -1) >@@ -306,6 +309,7 @@ > sHostbasedUsesNameFromPacketOnly, sClientAliveInterval, > sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2, > sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor, >+ sGssKeyEx, > sAcceptEnv, sPermitTunnel, > sMatch, sPermitOpen, sForceCommand, sChrootDirectory, > sUsePrivilegeSeparation, sAllowAgentForwarding, >@@ -369,10 +373,12 @@ > { "gssapiauthentication", sGssAuthentication, SSHCFG_ALL }, > { "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL }, > { "gssapistrictacceptorcheck", sGssStrictAcceptor, SSHCFG_GLOBAL }, >+ { "gssapikeyexchange", sGssKeyEx, SSHCFG_GLOBAL }, > #else > { "gssapiauthentication", sUnsupported, SSHCFG_ALL }, > { "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL }, > { "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL }, >+ { "gssapikeyexchange", sUnsupported, SSHCFG_GLOBAL }, > #endif > { "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL }, > { "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL }, >@@ -897,6 +903,10 @@ > 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; >Index: servconf.h >=================================================================== >--- servconf.h.orig 2009-07-26 14:46:23.000000000 +0100 >+++ servconf.h 2009-07-26 14:46:30.000000000 +0100 >@@ -91,6 +91,7 @@ > 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 >Index: ssh-gss.h >=================================================================== >--- ssh-gss.h.orig 2009-07-26 14:46:23.000000000 +0100 >+++ ssh-gss.h 2009-07-26 14:49:32.000000000 +0100 >@@ -60,6 +60,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; >@@ -97,6 +108,7 @@ > } 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); >@@ -119,6 +131,11 @@ > 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); >@@ -126,6 +143,8 @@ > 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 */ >Index: ssh_config >=================================================================== >--- ssh_config.orig 2009-07-26 14:46:23.000000000 +0100 >+++ ssh_config 2009-07-26 14:46:30.000000000 +0100 >@@ -26,6 +26,8 @@ > # HostbasedAuthentication no > # GSSAPIAuthentication no > # GSSAPIDelegateCredentials no >+# GSSAPIKeyExchange no >+# GSSAPITrustDNS no > # BatchMode no > # CheckHostIP yes > # AddressFamily any >Index: ssh_config.5 >=================================================================== >--- ssh_config.5.orig 2009-07-26 14:46:23.000000000 +0100 >+++ ssh_config.5 2009-07-26 14:49:32.000000000 +0100 >@@ -478,6 +478,12 @@ > The default is > .Dq no . > 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 is >+.Dq no . >+Note that this option applies to protocol version 2 only. > .It Cm GSSAPIDelegateCredentials > Forward (delegate) credentials to the server. > The default is >Index: sshconnect2.c >=================================================================== >--- sshconnect2.c.orig 2009-07-26 14:46:23.000000000 +0100 >+++ sshconnect2.c 2009-07-26 14:49:32.000000000 +0100 >@@ -104,9 +104,34 @@ > { > Kex *kex; > >+#ifdef GSSAPI >+ char *orig = NULL, *gss = NULL; >+ char *gss_host = NULL; >+#endif >+ > xxx_host = host; > xxx_hostaddr = hostaddr; > >+#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]; >+ >+ if (options.gss_trust_dns) >+ gss_host = (char *)get_canonical_hostname(1); >+ else >+ gss_host = host; >+ >+ 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 >+ > if (options.ciphers == (char *)-1) { > logit("No valid ciphers for protocol version 2 given, using defaults."); > options.ciphers = NULL; >@@ -134,6 +159,17 @@ > myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = > options.hostkeyalgorithms; > >+#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); >+ xfree(gss); >+ } >+#endif >+ > if (options.rekey_limit) > packet_set_rekey_limit((u_int32_t)options.rekey_limit); > >@@ -143,10 +179,25 @@ > kex->kex[KEX_DH_GRP14_SHA1] = kexdh_client; > kex->kex[KEX_DH_GEX_SHA1] = kexgex_client; > kex->kex[KEX_DH_GEX_SHA256] = kexgex_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_trust_dns = options.gss_trust_dns; >+ kex->gss_host = gss_host; >+ } >+#endif >+ > xxx_kex = kex; > > dispatch_run(DISPATCH_BLOCK, &kex->done, kex); >@@ -235,6 +286,7 @@ > void input_gssapi_hash(int type, u_int32_t, void *); > void input_gssapi_error(int, u_int32_t, void *); > void input_gssapi_errtok(int, u_int32_t, void *); >+int userauth_gsskeyex(Authctxt *authctxt); > #endif > > void userauth(Authctxt *, char *); >@@ -250,6 +302,10 @@ > > Authmethod authmethods[] = { > #ifdef GSSAPI >+ {"gssapi-keyex", >+ userauth_gsskeyex, >+ &options.gss_authentication, >+ NULL}, > {"gssapi-with-mic", > userauth_gssapi, > NULL, >@@ -552,7 +608,10 @@ > * 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) { >@@ -656,8 +715,8 @@ > { > 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"); >@@ -767,6 +826,48 @@ > xfree(msg); > xfree(lang); > } >+ >+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 >Index: sshd.c >=================================================================== >--- sshd.c.orig 2009-07-26 14:46:23.000000000 +0100 >+++ sshd.c 2009-07-26 14:46:30.000000000 +0100 >@@ -1534,10 +1534,13 @@ > 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); >@@ -2252,12 +2255,61 @@ > > myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = 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 */ > kex = kex_setup(myproposal); > kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server; > kex->kex[KEX_DH_GRP14_SHA1] = kexdh_server; > kex->kex[KEX_DH_GEX_SHA1] = kexgex_server; > kex->kex[KEX_DH_GEX_SHA256] = kexgex_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; >Index: sshd_config >=================================================================== >--- sshd_config.orig 2009-07-26 14:46:23.000000000 +0100 >+++ sshd_config 2009-07-26 14:46:30.000000000 +0100 >@@ -74,6 +74,7 @@ > #GSSAPIAuthentication no > #GSSAPICleanupCredentials yes > #GSSAPIStrictAcceptorCheck yes >+#GSSAPIKeyExchange no > > # Set this to 'yes' to enable PAM authentication, account processing, > # and session processing. If this is enabled, PAM authentication will >Index: sshd_config.5 >=================================================================== >--- sshd_config.5.orig 2009-07-26 14:46:23.000000000 +0100 >+++ sshd_config.5 2009-07-26 14:46:30.000000000 +0100 >@@ -374,6 +374,12 @@ > The default is > .Dq no . > 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 is >+.Dq no . >+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.
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 1242
:
1195
| 1664