Bugzilla – Attachment 1195 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
openssh-keyex.patch (text/plain), 49.78 KB, created by
Simon Wilkinson
on 2006-10-03 04:14:48 AEST
(
hide
)
Description:
Patch to add GSSAPI Key Exchange support
Filename:
MIME Type:
Creator:
Simon Wilkinson
Created:
2006-10-03 04:14:48 AEST
Size:
49.78 KB
patch
obsolete
>? ChangeLog.gssapi >? kexgssc.c.pretidy >? kexgsss.c.pretidy >? sshconnect2.c.pretidy >? sshd.c.pretidy >Index: Makefile.in >=================================================================== >RCS file: /cvs/openssh/Makefile.in,v >retrieving revision 1.282 >diff -u -r1.282 Makefile.in >--- Makefile.in 12 Sep 2006 11:54:10 -0000 1.282 >+++ Makefile.in 2 Oct 2006 17:59:02 -0000 >@@ -73,7 +73,7 @@ > 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 >+ entropy.o scard-opensc.o gss-genr.o kexgssc.o > > SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \ > sshconnect.o sshconnect1.o sshconnect2.o >@@ -86,7 +86,7 @@ > auth2-none.o auth2-passwd.o auth2-pubkey.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 > >Index: auth2-gss.c >=================================================================== >RCS file: /cvs/openssh/auth2-gss.c,v >retrieving revision 1.18 >diff -u -r1.18 auth2-gss.c >--- auth2-gss.c 1 Sep 2006 05:38:36 -0000 1.18 >+++ auth2-gss.c 2 Oct 2006 17:59:02 -0000 >@@ -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) >@@ -291,6 +324,12 @@ > dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL); > userauth_finish(authctxt, authenticated, "gssapi-with-mic"); > } >+ >+Authmethod method_gsskeyex = { >+ "gssapi-keyex", >+ userauth_gsskeyex, >+ &options.gss_authentication >+}; > > Authmethod method_gssapi = { > "gssapi-with-mic", >Index: auth2.c >=================================================================== >RCS file: /cvs/openssh/auth2.c,v >retrieving revision 1.142 >diff -u -r1.142 auth2.c >--- auth2.c 5 Aug 2006 02:39:39 -0000 1.142 >+++ auth2.c 2 Oct 2006 17:59:03 -0000 >@@ -64,6 +64,7 @@ > extern Authmethod method_kbdint; > extern Authmethod method_hostbased; > #ifdef GSSAPI >+extern Authmethod method_gsskeyex; > extern Authmethod method_gssapi; > #endif > >@@ -71,6 +72,7 @@ > &method_none, > &method_pubkey, > #ifdef GSSAPI >+ &method_gsskeyex, > &method_gssapi, > #endif > &method_passwd, >Index: gss-genr.c >=================================================================== >RCS file: /cvs/openssh/gss-genr.c,v >retrieving revision 1.19 >diff -u -r1.19 gss-genr.c >--- gss-genr.c 30 Aug 2006 01:08:04 -0000 1.19 >+++ gss-genr.c 2 Oct 2006 17:59:03 -0000 >@@ -39,12 +39,160 @@ > #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; >+ >+ gss_indicate_mechs(&min_status, &gss_supported); >+ >+ 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: >+ name += sizeof(KEX_GSS_GRP1_SHA1_ID) - 1; >+ break; >+ case KEX_GSS_GRP14_SHA1: >+ name += sizeof(KEX_GSS_GRP14_SHA1_ID) - 1; >+ break; >+ case KEX_GSS_GEX_SHA1: >+ 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) >@@ -262,6 +410,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); >@@ -269,6 +420,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) >@@ -297,6 +461,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 && >@@ -315,7 +483,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 >=================================================================== >RCS file: /cvs/openssh/gss-serv.c,v >retrieving revision 1.22 >diff -u -r1.22 gss-serv.c >--- gss-serv.c 1 Sep 2006 05:38:36 -0000 1.22 >+++ gss-serv.c 2 Oct 2006 17:59:03 -0000 >@@ -45,6 +45,7 @@ > #include "misc.h" > > #include "ssh-gss.h" >+#include "monitor_wrap.h" > > static ssh_gssapi_client gssapi_client = > { GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER, >@@ -65,6 +66,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) > { >@@ -301,16 +324,6 @@ > else > debug("ssh_gssapi_userok: Unknown GSSAPI mechanism"); > 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 >=================================================================== >RCS file: /cvs/openssh/kex.c,v >retrieving revision 1.83 >diff -u -r1.83 kex.c >--- kex.c 1 Sep 2006 05:38:36 -0000 1.83 >+++ kex.c 2 Oct 2006 17:59:03 -0000 >@@ -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 >@@ -322,6 +326,20 @@ > } else if (strcmp(k->name, KEX_DHGEX_SHA256) == 0) { > 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 >=================================================================== >RCS file: /cvs/openssh/kex.h,v >retrieving revision 1.47 >diff -u -r1.47 kex.h >--- kex.h 5 Aug 2006 02:39:40 -0000 1.47 >+++ kex.h 2 Oct 2006 17:59:03 -0000 >@@ -63,6 +63,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 > }; > >@@ -115,6 +118,10 @@ > sig_atomic_t done; > int flags; > const EVP_MD *evp_md; >+#ifdef GSSAPI >+ int gss_deleg_creds; >+ char *gss_host; >+#endif > char *client_version_string; > char *server_version_string; > int (*verify_host_key)(Key *); >@@ -136,6 +143,11 @@ > void kexdh_server(Kex *); > 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, >Index: kexgssc.c >=================================================================== >RCS file: kexgssc.c >diff -N kexgssc.c >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ kexgssc.c 2 Oct 2006 17:59:03 -0000 >@@ -0,0 +1,319 @@ >+/* >+ * Copyright (c) 2001-2005 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; >+ 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); >+ >+ shared_secret = BN_new(); >+ BN_bin2bn(kbuf,kout, shared_secret); >+ 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, slen, /* server host key */ >+ 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, 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 >=================================================================== >RCS file: kexgsss.c >diff -N kexgsss.c >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ kexgsss.c 2 Oct 2006 17:59:03 -0000 >@@ -0,0 +1,271 @@ >+/* >+ * Copyright (c) 2001-2005 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; >+ >+ /* 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()) >+ ssh_gssapi_server_mechanisms(); >+ >+ 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); >+ >+ shared_secret = BN_new(); >+ BN_bin2bn(kbuf, kout, shared_secret); >+ 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_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 >=================================================================== >RCS file: /cvs/openssh/key.c,v >retrieving revision 1.69 >diff -u -r1.69 key.c >--- key.c 1 Sep 2006 05:38:36 -0000 1.69 >+++ key.c 2 Oct 2006 17:59:03 -0000 >@@ -648,6 +648,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 >=================================================================== >RCS file: /cvs/openssh/key.h,v >retrieving revision 1.28 >diff -u -r1.28 key.h >--- key.h 5 Aug 2006 02:39:40 -0000 1.28 >+++ key.h 2 Oct 2006 17:59:03 -0000 >@@ -34,6 +34,7 @@ > KEY_RSA1, > KEY_RSA, > KEY_DSA, >+ KEY_NULL, > KEY_UNSPEC > }; > enum fp_type { >Index: monitor.c >=================================================================== >RCS file: /cvs/openssh/monitor.c,v >retrieving revision 1.120 >diff -u -r1.120 monitor.c >--- monitor.c 17 Sep 2006 02:00:13 -0000 1.120 >+++ monitor.c 2 Oct 2006 17:59:03 -0000 >@@ -163,6 +163,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 >@@ -232,11 +233,17 @@ > {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 > {MONITOR_REQ_MODULI, 0, mm_answer_moduli}, > {MONITOR_REQ_SIGN, 0, mm_answer_sign}, > {MONITOR_REQ_PTY, 0, mm_answer_pty}, >@@ -341,6 +348,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; > >@@ -417,6 +428,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); >@@ -1660,6 +1675,11 @@ > 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 >+ 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); >@@ -1901,6 +1921,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); > } >@@ -1951,4 +1972,42 @@ > /* 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; >+ >+ data.value = buffer_get_string(m, &len); >+ data.length = len; >+ if (data.length != 20) >+ fatal("%s: data length incorrect: %d", __func__, 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 */ >Index: monitor.h >=================================================================== >RCS file: /cvs/openssh/monitor.h,v >retrieving revision 1.21 >diff -u -r1.21 monitor.h >--- monitor.h 26 Mar 2006 03:30:02 -0000 1.21 >+++ monitor.h 2 Oct 2006 17:59:03 -0000 >@@ -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 >=================================================================== >RCS file: /cvs/openssh/monitor_wrap.c,v >retrieving revision 1.70 >diff -u -r1.70 monitor_wrap.c >--- monitor_wrap.c 1 Sep 2006 05:38:37 -0000 1.70 >+++ monitor_wrap.c 2 Oct 2006 17:59:04 -0000 >@@ -1224,4 +1224,27 @@ > 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 */ >Index: monitor_wrap.h >=================================================================== >RCS file: /cvs/openssh/monitor_wrap.h,v >retrieving revision 1.27 >diff -u -r1.27 monitor_wrap.h >--- monitor_wrap.h 5 Aug 2006 02:39:40 -0000 1.27 >+++ monitor_wrap.h 2 Oct 2006 17:59:04 -0000 >@@ -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 >=================================================================== >RCS file: /cvs/openssh/readconf.c,v >retrieving revision 1.136 >diff -u -r1.136 readconf.c >--- readconf.c 1 Sep 2006 05:38:37 -0000 1.136 >+++ readconf.c 2 Oct 2006 17:59:04 -0000 >@@ -127,6 +127,7 @@ > oClearAllForwardings, oNoHostAuthenticationForLocalhost, > oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout, > oAddressFamily, oGssAuthentication, oGssDelegateCreds, >+ oGssKeyEx, > oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly, > oSendEnv, oControlPath, oControlMaster, oHashKnownHosts, > oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand, >@@ -163,9 +164,11 @@ > { "afstokenpassing", oUnsupported }, > #if defined(GSSAPI) > { "gssapiauthentication", oGssAuthentication }, >+ { "gssapikeyexchange", oGssKeyEx }, > { "gssapidelegatecredentials", oGssDelegateCreds }, > #else > { "gssapiauthentication", oUnsupported }, >+ { "gssapikeyexchange", oUnsupported }, > { "gssapidelegatecredentials", oUnsupported }, > #endif > { "fallbacktorsh", oDeprecated }, >@@ -441,6 +444,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; >@@ -1010,6 +1017,7 @@ > 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; >@@ -1099,6 +1107,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->password_authentication == -1) >Index: readconf.h >=================================================================== >RCS file: /cvs/openssh/readconf.h,v >retrieving revision 1.63 >diff -u -r1.63 readconf.h >--- readconf.h 5 Aug 2006 02:39:40 -0000 1.63 >+++ readconf.h 2 Oct 2006 17:59:04 -0000 >@@ -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 password_authentication; /* Try password > * authentication. */ >Index: servconf.c >=================================================================== >RCS file: /cvs/openssh/servconf.c,v >retrieving revision 1.156 >diff -u -r1.156 servconf.c >--- servconf.c 18 Aug 2006 14:23:15 -0000 1.156 >+++ servconf.c 2 Oct 2006 17:59:07 -0000 >@@ -90,6 +90,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->password_authentication = -1; > options->kbd_interactive_authentication = -1; >@@ -204,6 +205,8 @@ > 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->password_authentication == -1) >@@ -290,7 +293,8 @@ > sBanner, sUseDNS, sHostbasedAuthentication, > sHostbasedUsesNameFromPacketOnly, sClientAliveInterval, > sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2, >- sGssAuthentication, sGssCleanupCreds, sAcceptEnv, sPermitTunnel, >+ sGssAuthentication, sGssKeyEx, sGssCleanupCreds, >+ sAcceptEnv, sPermitTunnel, > sMatch, sPermitOpen, sForceCommand, > sUsePrivilegeSeparation, > sDeprecated, sUnsupported >@@ -350,9 +354,11 @@ > { "afstokenpassing", sUnsupported, SSHCFG_GLOBAL }, > #ifdef GSSAPI > { "gssapiauthentication", sGssAuthentication, SSHCFG_GLOBAL }, >+ { "gssapikeyexchange", sGssKeyEx, SSHCFG_GLOBAL }, > { "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL }, > #else > { "gssapiauthentication", sUnsupported, SSHCFG_GLOBAL }, >+ { "gssapikeyexchange", sUnsupported, SSHCFG_GLOBAL }, > { "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL }, > #endif > { "passwordauthentication", sPasswordAuthentication, SSHCFG_GLOBAL }, >@@ -870,6 +876,10 @@ > > case sGssAuthentication: > intptr = &options->gss_authentication; >+ goto parse_flag; >+ >+ case sGssKeyEx: >+ intptr = &options->gss_keyex; > goto parse_flag; > > case sGssCleanupCreds: >Index: servconf.h >=================================================================== >RCS file: /cvs/openssh/servconf.h,v >retrieving revision 1.71 >diff -u -r1.71 servconf.h >--- servconf.h 18 Aug 2006 14:23:15 -0000 1.71 >+++ servconf.h 2 Oct 2006 17:59:07 -0000 >@@ -87,6 +87,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 password_authentication; /* If true, permit password > * authentication. */ >Index: ssh-gss.h >=================================================================== >RCS file: /cvs/openssh/ssh-gss.h,v >retrieving revision 1.11 >diff -u -r1.11 ssh-gss.h >--- ssh-gss.h 18 Aug 2006 14:46:44 -0000 1.11 >+++ ssh-gss.h 2 Oct 2006 17:59:07 -0000 >@@ -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); >@@ -121,12 +133,19 @@ > 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 *); > int ssh_gssapi_userok(char *name); > OM_uint32 ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t); > 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 */ >Index: ssh_config.5 >=================================================================== >RCS file: /cvs/openssh/ssh_config.5,v >retrieving revision 1.97 >diff -u -r1.97 ssh_config.5 >--- ssh_config.5 5 Aug 2006 01:34:51 -0000 1.97 >+++ ssh_config.5 2 Oct 2006 17:59:08 -0000 >@@ -479,6 +479,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 >=================================================================== >RCS file: /cvs/openssh/sshconnect2.c,v >retrieving revision 1.153 >diff -u -r1.153 sshconnect2.c >--- sshconnect2.c 1 Sep 2006 05:38:37 -0000 1.153 >+++ sshconnect2.c 2 Oct 2006 17:59:10 -0000 >@@ -98,9 +98,28 @@ > { > Kex *kex; > >+#ifdef GSSAPI >+ char *orig = NULL, *gss = 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]; >+ >+ gss = ssh_gssapi_client_mechanisms(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; >@@ -128,6 +147,16 @@ > 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); >+ } >+#endif >+ > if (options.rekey_limit) > packet_set_rekey_limit(options.rekey_limit); > >@@ -137,10 +166,20 @@ > 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 >+ 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 >+ kex->gss_deleg_creds = options.gss_deleg_creds; >+ kex->gss_host = host; >+#endif >+ > xxx_kex = kex; > > dispatch_run(DISPATCH_BLOCK, &kex->done, kex); >@@ -223,6 +262,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 *); >@@ -238,6 +278,10 @@ > > Authmethod authmethods[] = { > #ifdef GSSAPI >+ {"gssapi-keyex", >+ userauth_gsskeyex, >+ &options.gss_authentication, >+ NULL}, > {"gssapi-with-mic", > userauth_gssapi, > &options.gss_authentication, >@@ -716,6 +760,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 >=================================================================== >RCS file: /cvs/openssh/sshd.c,v >retrieving revision 1.358 >diff -u -r1.358 sshd.c >--- sshd.c 17 Sep 2006 04:04:46 -0000 1.358 >+++ sshd.c 2 Oct 2006 17:59:13 -0000 >@@ -1472,10 +1472,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); >@@ -2108,12 +2111,59 @@ > > 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 >+ 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.5 >=================================================================== >RCS file: /cvs/openssh/sshd_config.5,v >retrieving revision 1.76 >diff -u -r1.76 sshd_config.5 >--- sshd_config.5 30 Aug 2006 01:06:34 -0000 1.76 >+++ sshd_config.5 2 Oct 2006 17:59:14 -0000 >@@ -320,6 +320,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