summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.in4
-rw-r--r--auth2-gss.c39
-rw-r--r--auth2.c2
-rw-r--r--gss-genr.c156
-rw-r--r--gss-serv.c32
-rw-r--r--kex.c9
-rw-r--r--kex.h9
-rw-r--r--kexgssc.c242
-rw-r--r--kexgsss.c204
-rw-r--r--key.c2
-rw-r--r--key.h1
-rw-r--r--monitor.c54
-rw-r--r--monitor.h1
-rw-r--r--monitor_wrap.c21
-rw-r--r--monitor_wrap.h1
-rw-r--r--ssh-gss.h16
-rw-r--r--sshconnect2.c80
-rw-r--r--sshd.c58
18 files changed, 913 insertions, 18 deletions
diff --git a/Makefile.in b/Makefile.in
index bca425d36..e0be3d04b 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -71,7 +71,7 @@ LIBSSH_OBJS=acss.o authfd.o authfile.o bufaux.o buffer.o \
71 atomicio.o key.o dispatch.o kex.o mac.o uidswap.o uuencode.o misc.o \ 71 atomicio.o key.o dispatch.o kex.o mac.o uidswap.o uuencode.o misc.o \
72 monitor_fdpass.o rijndael.o ssh-dss.o ssh-rsa.o dh.o kexdh.o \ 72 monitor_fdpass.o rijndael.o ssh-dss.o ssh-rsa.o dh.o kexdh.o \
73 kexgex.o kexdhc.o kexgexc.o scard.o msg.o progressmeter.o dns.o \ 73 kexgex.o kexdhc.o kexgexc.o scard.o msg.o progressmeter.o dns.o \
74 entropy.o scard-opensc.o gss-genr.o 74 entropy.o scard-opensc.o gss-genr.o kexgssc.o
75 75
76SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \ 76SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \
77 sshconnect.o sshconnect1.o sshconnect2.o 77 sshconnect.o sshconnect1.o sshconnect2.o
@@ -84,7 +84,7 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o auth-rsa.o auth-rh-rsa.o \
84 auth2-none.o auth2-passwd.o auth2-pubkey.o \ 84 auth2-none.o auth2-passwd.o auth2-pubkey.o \
85 monitor_mm.o monitor.o monitor_wrap.o kexdhs.o kexgexs.o \ 85 monitor_mm.o monitor.o monitor_wrap.o kexdhs.o kexgexs.o \
86 auth-krb5.o \ 86 auth-krb5.o \
87 auth2-gss.o gss-serv.o gss-serv-krb5.o \ 87 auth2-gss.o gss-serv.o gss-serv-krb5.o kexgsss.o\
88 loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \ 88 loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \
89 audit.o audit-bsm.o 89 audit.o audit-bsm.o
90 90
diff --git a/auth2-gss.c b/auth2-gss.c
index 3289ba18e..0ac405496 100644
--- a/auth2-gss.c
+++ b/auth2-gss.c
@@ -47,6 +47,39 @@ static void input_gssapi_mic(int type, u_int32_t plen, void *ctxt);
47static void input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt); 47static void input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt);
48static void input_gssapi_errtok(int, u_int32_t, void *); 48static void input_gssapi_errtok(int, u_int32_t, void *);
49 49
50/*
51 * The 'gssapi_keyex' userauth mechanism.
52 */
53static int
54userauth_gsskeyex(Authctxt *authctxt)
55{
56 int authenticated = 0;
57 Buffer b;
58 gss_buffer_desc mic, gssbuf;
59 u_int len;
60
61 mic.value = packet_get_string(&len);
62 mic.length = len;
63
64 packet_check_eom();
65
66 ssh_gssapi_buildmic(&b, authctxt->user, authctxt->service,
67 "gssapi-keyex");
68
69 gssbuf.value = buffer_ptr(&b);
70 gssbuf.length = buffer_len(&b);
71
72 /* gss_kex_context is NULL with privsep, so we can't check it here */
73 if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gss_kex_context,
74 &gssbuf, &mic))))
75 authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user));
76
77 buffer_free(&b);
78 xfree(mic.value);
79
80 return (authenticated);
81}
82
50/* 83/*
51 * We only support those mechanisms that we know about (ie ones that we know 84 * We only support those mechanisms that we know about (ie ones that we know
52 * how to check local user kuserok and the like 85 * how to check local user kuserok and the like
@@ -286,6 +319,12 @@ input_gssapi_mic(int type, u_int32_t plen, void *ctxt)
286 userauth_finish(authctxt, authenticated, "gssapi-with-mic"); 319 userauth_finish(authctxt, authenticated, "gssapi-with-mic");
287} 320}
288 321
322Authmethod method_gsskeyex = {
323 "gssapi-keyx",
324 userauth_gsskeyex,
325 &options.gss_authentication
326};
327
289Authmethod method_gssapi = { 328Authmethod method_gssapi = {
290 "gssapi-with-mic", 329 "gssapi-with-mic",
291 userauth_gssapi, 330 userauth_gssapi,
diff --git a/auth2.c b/auth2.c
index 2265d311e..46068b285 100644
--- a/auth2.c
+++ b/auth2.c
@@ -55,6 +55,7 @@ extern Authmethod method_passwd;
55extern Authmethod method_kbdint; 55extern Authmethod method_kbdint;
56extern Authmethod method_hostbased; 56extern Authmethod method_hostbased;
57#ifdef GSSAPI 57#ifdef GSSAPI
58extern Authmethod method_gsskeyex;
58extern Authmethod method_gssapi; 59extern Authmethod method_gssapi;
59#endif 60#endif
60 61
@@ -62,6 +63,7 @@ Authmethod *authmethods[] = {
62 &method_none, 63 &method_none,
63 &method_pubkey, 64 &method_pubkey,
64#ifdef GSSAPI 65#ifdef GSSAPI
66 &method_gsskeyex,
65 &method_gssapi, 67 &method_gssapi,
66#endif 68#endif
67 &method_passwd, 69 &method_passwd,
diff --git a/gss-genr.c b/gss-genr.c
index 3f5727b3e..36925df4e 100644
--- a/gss-genr.c
+++ b/gss-genr.c
@@ -34,12 +34,137 @@
34#include "log.h" 34#include "log.h"
35#include "monitor_wrap.h" 35#include "monitor_wrap.h"
36#include "ssh2.h" 36#include "ssh2.h"
37#include <openssl/evp.h>
37 38
38#include "ssh-gss.h" 39#include "ssh-gss.h"
39 40
40extern u_char *session_id2; 41extern u_char *session_id2;
41extern u_int session_id2_len; 42extern u_int session_id2_len;
42 43
44typedef struct {
45 char *encoded;
46 gss_OID oid;
47} ssh_gss_kex_mapping;
48
49/*
50 * XXX - It would be nice to find a more elegant way of handling the
51 * XXX passing of the key exchange context to the userauth routines
52 */
53
54Gssctxt *gss_kex_context = NULL;
55
56static ssh_gss_kex_mapping *gss_enc2oid = NULL;
57
58/*
59 * Return a list of the gss-group1-sha1 mechanisms supported by this program
60 *
61 * We test mechanisms to ensure that we can use them, to avoid starting
62 * a key exchange with a bad mechanism
63 */
64
65
66char *
67ssh_gssapi_client_mechanisms(char *host) {
68 gss_OID_set gss_supported;
69 OM_uint32 min_status;
70
71 gss_indicate_mechs(&min_status, &gss_supported);
72
73 return(ssh_gssapi_kex_mechs(gss_supported, ssh_gssapi_check_mechanism,
74 (void *)host));
75}
76
77char *
78ssh_gssapi_kex_mechs(gss_OID_set gss_supported, ssh_gssapi_check_fn *check,
79 void *data) {
80 Buffer buf;
81 int i, oidpos, enclen;
82 char *mechs, *encoded;
83 char digest[EVP_MAX_MD_SIZE];
84 char deroid[2];
85 const EVP_MD *evp_md = EVP_md5();
86 EVP_MD_CTX md;
87
88 evp_md = EVP_md5();
89
90 if (gss_enc2oid != NULL) {
91 for (i=0;gss_enc2oid[i].encoded!=NULL;i++)
92 xfree(gss_enc2oid[i].encoded);
93 xfree(gss_enc2oid);
94 }
95
96 gss_enc2oid = xmalloc(sizeof(ssh_gss_kex_mapping)*
97 (gss_supported->count+1));
98
99 buffer_init(&buf);
100
101 oidpos = 0;
102 for (i=0;i<gss_supported->count;i++) {
103 if (gss_supported->elements[i].length<128 &&
104 (*check)(&(gss_supported->elements[i]), data)) {
105
106 deroid[0] = SSH_GSS_OIDTYPE;
107 deroid[1] = gss_supported->elements[i].length;
108 EVP_DigestInit(&md, evp_md);
109 EVP_DigestUpdate(&md, deroid, 2);
110 EVP_DigestUpdate(&md,
111 gss_supported->elements[i].elements,
112 gss_supported->elements[i].length);
113 EVP_DigestFinal(&md, digest, NULL);
114
115 encoded = xmalloc(EVP_MD_size(evp_md)*2);
116 enclen = __b64_ntop(digest, EVP_MD_size(evp_md),
117 encoded, EVP_MD_size(evp_md)*2);
118
119 if (oidpos != 0)
120 buffer_put_char(&buf,',');
121
122 buffer_append(&buf, KEX_GSS_SHA1,
123 sizeof(KEX_GSS_SHA1)-1);
124 buffer_append(&buf, encoded, enclen);
125
126 gss_enc2oid[oidpos].oid = &(gss_supported->elements[i]);
127 gss_enc2oid[oidpos].encoded = encoded;
128 oidpos++;
129 }
130 }
131 gss_enc2oid[oidpos].oid = NULL;
132 gss_enc2oid[oidpos].encoded = NULL;
133
134 buffer_put_char(&buf,'\0');
135
136 mechs = xmalloc(buffer_len(&buf));
137 buffer_get(&buf, mechs, buffer_len(&buf));
138 buffer_free(&buf);
139
140 if (strlen(mechs) == 0) {
141 xfree(mechs);
142 mechs = NULL;
143 }
144
145 return (mechs);
146}
147
148gss_OID
149ssh_gssapi_id_kex(Gssctxt *ctx, char *name) {
150 int i = 0;
151
152 if (strncmp(name, KEX_GSS_SHA1, sizeof(KEX_GSS_SHA1)-1) != 0)
153 return NULL;
154
155 name+=sizeof(KEX_GSS_SHA1)-1; /* Skip ID string */
156
157 while (gss_enc2oid[i].encoded != NULL &&
158 strcmp(name,gss_enc2oid[i].encoded)!=0) {
159 i++;
160 }
161
162 if (gss_enc2oid[i].oid != NULL && ctx != NULL)
163 ssh_gssapi_set_oid(ctx,gss_enc2oid[i].oid);
164
165 return gss_enc2oid[i].oid;
166}
167
43/* Check that the OID in a data stream matches that in the context */ 168/* Check that the OID in a data stream matches that in the context */
44int 169int
45ssh_gssapi_check_oid(Gssctxt *ctx, void *data, size_t len) 170ssh_gssapi_check_oid(Gssctxt *ctx, void *data, size_t len)
@@ -250,6 +375,9 @@ ssh_gssapi_acquire_cred(Gssctxt *ctx)
250OM_uint32 375OM_uint32
251ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash) 376ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash)
252{ 377{
378 if (ctx == NULL)
379 return -1;
380
253 if ((ctx->major = gss_get_mic(&ctx->minor, ctx->context, 381 if ((ctx->major = gss_get_mic(&ctx->minor, ctx->context,
254 GSS_C_QOP_DEFAULT, buffer, hash))) 382 GSS_C_QOP_DEFAULT, buffer, hash)))
255 ssh_gssapi_error(ctx); 383 ssh_gssapi_error(ctx);
@@ -257,6 +385,19 @@ ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash)
257 return (ctx->major); 385 return (ctx->major);
258} 386}
259 387
388/* Priviledged when used by server */
389OM_uint32
390ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic)
391{
392 if (ctx == NULL)
393 return -1;
394
395 ctx->major = gss_verify_mic(&ctx->minor, ctx->context,
396 gssbuf, gssmic, NULL);
397
398 return (ctx->major);
399}
400
260void 401void
261ssh_gssapi_buildmic(Buffer *b, const char *user, const char *service, 402ssh_gssapi_buildmic(Buffer *b, const char *user, const char *service,
262 const char *context) 403 const char *context)
@@ -278,4 +419,19 @@ ssh_gssapi_server_ctx(Gssctxt **ctx, gss_OID oid) {
278 return (ssh_gssapi_acquire_cred(*ctx)); 419 return (ssh_gssapi_acquire_cred(*ctx));
279} 420}
280 421
422int
423ssh_gssapi_check_mechanism(gss_OID oid, void *host) {
424 Gssctxt * ctx = NULL;
425 gss_buffer_desc token;
426 OM_uint32 major, minor;
427
428 ssh_gssapi_build_ctx(&ctx);
429 ssh_gssapi_set_oid(ctx, oid);
430 ssh_gssapi_import_name(ctx, host);
431 major = ssh_gssapi_init_ctx(ctx, 0, GSS_C_NO_BUFFER, &token, NULL);
432 gss_release_buffer(&minor, &token);
433 ssh_gssapi_delete_ctx(&ctx);
434 return (!GSS_ERROR(major));
435}
436
281#endif /* GSSAPI */ 437#endif /* GSSAPI */
diff --git a/gss-serv.c b/gss-serv.c
index de32a3f2e..fad79a1b4 100644
--- a/gss-serv.c
+++ b/gss-serv.c
@@ -62,6 +62,28 @@ ssh_gssapi_mech* supported_mechs[]= {
62}; 62};
63 63
64/* Unpriviledged */ 64/* Unpriviledged */
65char *
66ssh_gssapi_server_mechanisms() {
67 gss_OID_set supported;
68
69 ssh_gssapi_supported_oids(&supported);
70 return (ssh_gssapi_kex_mechs(supported, &ssh_gssapi_server_check_mech,
71 NULL));
72}
73
74/* Unpriviledged */
75int
76ssh_gssapi_server_check_mech(gss_OID oid, void *data) {
77 Gssctxt * ctx = NULL;
78 int res;
79
80 res = !GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctx, oid)));
81 ssh_gssapi_delete_ctx(&ctx);
82
83 return (res);
84}
85
86/* Unpriviledged */
65void 87void
66ssh_gssapi_supported_oids(gss_OID_set *oidset) 88ssh_gssapi_supported_oids(gss_OID_set *oidset)
67{ 89{
@@ -287,14 +309,4 @@ ssh_gssapi_userok(char *user)
287 return (0); 309 return (0);
288} 310}
289 311
290/* Priviledged */
291OM_uint32
292ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic)
293{
294 ctx->major = gss_verify_mic(&ctx->minor, ctx->context,
295 gssbuf, gssmic, NULL);
296
297 return (ctx->major);
298}
299
300#endif 312#endif
diff --git a/kex.c b/kex.c
index a668346c3..3d6f3ab54 100644
--- a/kex.c
+++ b/kex.c
@@ -42,6 +42,10 @@ RCSID("$OpenBSD: kex.c,v 1.60 2004/06/21 17:36:31 avsm Exp $");
42#include "dispatch.h" 42#include "dispatch.h"
43#include "monitor.h" 43#include "monitor.h"
44 44
45#ifdef GSSAPI
46#include "ssh-gss.h"
47#endif
48
45#define KEX_COOKIE_LEN 16 49#define KEX_COOKIE_LEN 16
46 50
47/* prototype */ 51/* prototype */
@@ -297,6 +301,11 @@ choose_kex(Kex *k, char *client, char *server)
297 k->kex_type = KEX_DH_GRP14_SHA1; 301 k->kex_type = KEX_DH_GRP14_SHA1;
298 } else if (strcmp(k->name, KEX_DHGEX) == 0) { 302 } else if (strcmp(k->name, KEX_DHGEX) == 0) {
299 k->kex_type = KEX_DH_GEX_SHA1; 303 k->kex_type = KEX_DH_GEX_SHA1;
304#ifdef GSSAPI
305 } else if (strncmp(k->name, KEX_GSS_SHA1,
306 sizeof(KEX_GSS_SHA1)-1) == 0) {
307 k->kex_type = KEX_GSS_GRP1_SHA1;
308#endif
300 } else 309 } else
301 fatal("bad kex alg %s", k->name); 310 fatal("bad kex alg %s", k->name);
302} 311}
diff --git a/kex.h b/kex.h
index d9e9d6522..9536d506c 100644
--- a/kex.h
+++ b/kex.h
@@ -59,6 +59,7 @@ enum kex_exchange {
59 KEX_DH_GRP1_SHA1, 59 KEX_DH_GRP1_SHA1,
60 KEX_DH_GRP14_SHA1, 60 KEX_DH_GRP14_SHA1,
61 KEX_DH_GEX_SHA1, 61 KEX_DH_GEX_SHA1,
62 KEX_GSS_GRP1_SHA1,
62 KEX_MAX 63 KEX_MAX
63}; 64};
64 65
@@ -110,6 +111,9 @@ struct Kex {
110 Buffer peer; 111 Buffer peer;
111 int done; 112 int done;
112 int flags; 113 int flags;
114#ifdef GSSAPI
115 int gss_deleg_creds;
116#endif
113 char *client_version_string; 117 char *client_version_string;
114 char *server_version_string; 118 char *server_version_string;
115 int (*verify_host_key)(Key *); 119 int (*verify_host_key)(Key *);
@@ -132,6 +136,11 @@ void kexdh_server(Kex *);
132void kexgex_client(Kex *); 136void kexgex_client(Kex *);
133void kexgex_server(Kex *); 137void kexgex_server(Kex *);
134 138
139#ifdef GSSAPI
140void kexgss_client(Kex *);
141void kexgss_server(Kex *);
142#endif
143
135u_char * 144u_char *
136kex_dh_hash(char *, char *, char *, int, char *, int, u_char *, int, 145kex_dh_hash(char *, char *, char *, int, char *, int, u_char *, int,
137 BIGNUM *, BIGNUM *, BIGNUM *); 146 BIGNUM *, BIGNUM *, BIGNUM *);
diff --git a/kexgssc.c b/kexgssc.c
new file mode 100644
index 000000000..eee96dd23
--- /dev/null
+++ b/kexgssc.c
@@ -0,0 +1,242 @@
1/*
2 * Copyright (c) 2001-2004 Simon Wilkinson. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 */
24
25#include "includes.h"
26
27#ifdef GSSAPI
28
29#include <openssl/crypto.h>
30#include <openssl/bn.h>
31
32#include "xmalloc.h"
33#include "buffer.h"
34#include "bufaux.h"
35#include "kex.h"
36#include "log.h"
37#include "packet.h"
38#include "dh.h"
39#include "canohost.h"
40#include "ssh2.h"
41#include "ssh-gss.h"
42
43void
44kexgss_client(Kex *kex) {
45 gss_buffer_desc gssbuf, send_tok, recv_tok, msg_tok, *token_ptr;
46 Gssctxt *ctxt;
47 OM_uint32 maj_status, min_status, ret_flags;
48 unsigned int klen, kout;
49 DH *dh;
50 BIGNUM *dh_server_pub = 0;
51 BIGNUM *shared_secret = 0;
52 unsigned char *kbuf;
53 unsigned char *hash;
54 unsigned char *serverhostkey;
55 char *msg;
56 char *lang;
57 int type = 0;
58 int first = 1;
59 int slen = 0;
60 u_int strlen;
61
62 ssh_gssapi_build_ctx(&ctxt);
63 if (ssh_gssapi_id_kex(ctxt,kex->name) == NULL)
64 fatal("Couldn't identify host exchange");
65
66 if (ssh_gssapi_import_name(ctxt,get_canonical_hostname(1)))
67 fatal("Couldn't import hostname ");
68
69 /* This code should match that in ssh_dh1_client */
70
71 /* Step 1 - e is dh->pub_key */
72 dh = dh_new_group1();
73 dh_gen_key(dh, kex->we_need * 8);
74
75 /* This is f, we initialise it now to make life easier */
76 dh_server_pub = BN_new();
77 if (dh_server_pub == NULL)
78 fatal("dh_server_pub == NULL");
79
80 token_ptr = GSS_C_NO_BUFFER;
81
82 do {
83 debug("Calling gss_init_sec_context");
84
85 maj_status = ssh_gssapi_init_ctx(ctxt,
86 kex->gss_deleg_creds, token_ptr, &send_tok,
87 &ret_flags);
88
89 if (GSS_ERROR(maj_status)) {
90 if (send_tok.length != 0) {
91 packet_start(SSH2_MSG_KEXGSS_CONTINUE);
92 packet_put_string(send_tok.value,
93 send_tok.length);
94 }
95 fatal("gss_init_context failed");
96 }
97
98 /* If we've got an old receive buffer get rid of it */
99 if (token_ptr != GSS_C_NO_BUFFER)
100 (void) gss_release_buffer(&min_status, &recv_tok);
101
102 if (maj_status == GSS_S_COMPLETE) {
103 /* If mutual state flag is not true, kex fails */
104 if (!(ret_flags & GSS_C_MUTUAL_FLAG))
105 fatal("Mutual authentication failed");
106
107 /* If integ avail flag is not true kex fails */
108 if (!(ret_flags & GSS_C_INTEG_FLAG))
109 fatal("Integrity check failed");
110 }
111
112 /*
113 * If we have data to send, then the last message that we
114 * received cannot have been a 'complete'.
115 */
116 if (send_tok.length != 0) {
117 if (first) {
118 packet_start(SSH2_MSG_KEXGSS_INIT);
119 packet_put_string(send_tok.value,
120 send_tok.length);
121 packet_put_bignum2(dh->pub_key);
122 first = 0;
123 } else {
124 packet_start(SSH2_MSG_KEXGSS_CONTINUE);
125 packet_put_string(send_tok.value,
126 send_tok.length);
127 }
128 packet_send();
129
130 /* If we've sent them data, they should reply */
131
132 type = packet_read();
133 switch (type) {
134 case SSH2_MSG_KEXGSS_HOSTKEY:
135 debug("Received KEXGSS_HOSTKEY");
136 serverhostkey = packet_get_string(&slen);
137 break;
138 case SSH2_MSG_KEXGSS_CONTINUE:
139 debug("Received GSSAPI_CONTINUE");
140 if (maj_status == GSS_S_COMPLETE)
141 fatal("GSSAPI Continue received from server when complete");
142 recv_tok.value = packet_get_string(&strlen);
143 recv_tok.length = strlen;
144 break;
145 case SSH2_MSG_KEXGSS_COMPLETE:
146 debug("Received GSSAPI_COMPLETE");
147 packet_get_bignum2(dh_server_pub);
148 msg_tok.value = packet_get_string(&strlen);
149 msg_tok.length = strlen;
150
151 /* Is there a token included? */
152 if (packet_get_char()) {
153 recv_tok.value=
154 packet_get_string(&strlen);
155 recv_tok.length = strlen;
156 /* If we're already complete - protocol error */
157 if (maj_status == GSS_S_COMPLETE)
158 packet_disconnect("Protocol error: received token when complete");
159 } else {
160 /* No token included */
161 if (maj_status != GSS_S_COMPLETE)
162 packet_disconnect("Protocol error: did not receive final token");
163 }
164 break;
165 case SSH2_MSG_KEXGSS_ERROR:
166 debug("Received Error");
167 maj_status = packet_get_int();
168 min_status = packet_get_int();
169 msg = packet_get_string(NULL);
170 lang = packet_get_string(NULL);
171 fprintf(stderr,"GSSAPI Error: \n%s",msg);
172 default:
173 packet_disconnect("Protocol error: didn't expect packet type %d",
174 type);
175 }
176 token_ptr = &recv_tok;
177 } else {
178 /* No data, and not complete */
179 if (maj_status != GSS_S_COMPLETE)
180 fatal("Not complete, and no token output");
181 }
182 } while (maj_status & GSS_S_CONTINUE_NEEDED);
183
184 /*
185 * We _must_ have received a COMPLETE message in reply from the
186 * server, which will have set dh_server_pub and msg_tok
187 */
188
189 if (type!=SSH2_MSG_KEXGSS_COMPLETE)
190 fatal("Didn't receive a SSH2_MSG_KEXGSS_COMPLETE when I expected it");
191
192 /* Check f in range [1, p-1] */
193 if (!dh_pub_is_valid(dh, dh_server_pub))
194 packet_disconnect("bad server public DH value");
195
196 /* compute K=f^x mod p */
197 klen = DH_size(dh);
198 kbuf = xmalloc(klen);
199 kout = DH_compute_key(kbuf, dh_server_pub, dh);
200
201 shared_secret = BN_new();
202 BN_bin2bn(kbuf,kout, shared_secret);
203 memset(kbuf, 0, klen);
204 xfree(kbuf);
205
206 /* The GSS hash is identical to the DH one */
207 hash = kex_dh_hash( kex->client_version_string,
208 kex->server_version_string,
209 buffer_ptr(&kex->my), buffer_len(&kex->my),
210 buffer_ptr(&kex->peer), buffer_len(&kex->peer),
211 serverhostkey, slen, /* server host key */
212 dh->pub_key, /* e */
213 dh_server_pub, /* f */
214 shared_secret /* K */
215 );
216
217 gssbuf.value = hash;
218 gssbuf.length = 20;
219
220 /* Verify that the hash matches the MIC we just got. */
221 if (GSS_ERROR(ssh_gssapi_checkmic(ctxt, &gssbuf, &msg_tok)))
222 packet_disconnect("Hash's MIC didn't verify");
223
224 DH_free(dh);
225 /* save session id */
226 if (kex->session_id == NULL) {
227 kex->session_id_len = 20;
228 kex->session_id = xmalloc(kex->session_id_len);
229 memcpy(kex->session_id, hash, kex->session_id_len);
230 }
231
232 if (gss_kex_context == NULL)
233 gss_kex_context = ctxt;
234 else
235 ssh_gssapi_delete_ctx(&ctxt);
236
237 kex_derive_keys(kex, hash, shared_secret);
238 BN_clear_free(shared_secret);
239 kex_finish(kex);
240}
241
242#endif /* GSSAPI */
diff --git a/kexgsss.c b/kexgsss.c
new file mode 100644
index 000000000..80c133ac9
--- /dev/null
+++ b/kexgsss.c
@@ -0,0 +1,204 @@
1/*
2 * Copyright (c) 2001-2004 Simon Wilkinson. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 */
24
25#include "includes.h"
26
27#ifdef GSSAPI
28
29#include <openssl/crypto.h>
30#include <openssl/bn.h>
31
32#include "xmalloc.h"
33#include "buffer.h"
34#include "bufaux.h"
35#include "kex.h"
36#include "log.h"
37#include "packet.h"
38#include "dh.h"
39#include "ssh2.h"
40#include "ssh-gss.h"
41#include "monitor_wrap.h"
42
43void
44kexgss_server(Kex *kex)
45{
46 OM_uint32 maj_status, min_status;
47
48 /*
49 * Some GSSAPI implementations use the input value of ret_flags (an
50 * output variable) as a means of triggering mechanism specific
51 * features. Initializing it to zero avoids inadvertently
52 * activating this non-standard behaviour.
53 */
54
55 OM_uint32 ret_flags = 0;
56 gss_buffer_desc gssbuf, send_tok, recv_tok, msg_tok;
57 Gssctxt *ctxt = NULL;
58 unsigned int klen, kout;
59 unsigned char *kbuf, *hash;
60 DH *dh;
61 BIGNUM *shared_secret = NULL;
62 BIGNUM *dh_client_pub = NULL;
63 int type =0;
64 u_int slen;
65 gss_OID oid;
66
67 /* Initialise GSSAPI */
68
69 debug2("%s: Identifying %s", __func__, kex->name);
70 oid = ssh_gssapi_id_kex(NULL, kex->name);
71 if (oid == NULL)
72 fatal("Unknown gssapi mechanism");
73
74 debug2("%s: Acquiring credentials", __func__);
75
76 if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, oid))))
77 fatal("Unable to acquire credentials for the server");
78
79 do {
80 debug("Wait SSH2_MSG_GSSAPI_INIT");
81 type = packet_read();
82 switch(type) {
83 case SSH2_MSG_KEXGSS_INIT:
84 if (dh_client_pub != NULL)
85 fatal("Received KEXGSS_INIT after initialising");
86 recv_tok.value = packet_get_string(&slen);
87 recv_tok.length = slen;
88
89 dh_client_pub = BN_new();
90
91 if (dh_client_pub == NULL)
92 fatal("dh_client_pub == NULL");
93 packet_get_bignum2(dh_client_pub);
94
95 /* Send SSH_MSG_KEXGSS_HOSTKEY here, if we want */
96 break;
97 case SSH2_MSG_KEXGSS_CONTINUE:
98 recv_tok.value = packet_get_string(&slen);
99 recv_tok.length = slen;
100 break;
101 default:
102 packet_disconnect(
103 "Protocol error: didn't expect packet type %d",
104 type);
105 }
106
107 maj_status = PRIVSEP(ssh_gssapi_accept_ctx(ctxt, &recv_tok,
108 &send_tok, &ret_flags));
109
110 gss_release_buffer(&min_status, &recv_tok);
111
112 if (maj_status != GSS_S_COMPLETE && send_tok.length == 0)
113 fatal("Zero length token output when incomplete");
114
115 if (dh_client_pub == NULL)
116 fatal("No client public key");
117
118 if (maj_status & GSS_S_CONTINUE_NEEDED) {
119 debug("Sending GSSAPI_CONTINUE");
120 packet_start(SSH2_MSG_KEXGSS_CONTINUE);
121 packet_put_string(send_tok.value, send_tok.length);
122 packet_send();
123 gss_release_buffer(&min_status, &send_tok);
124 }
125 } while (maj_status & GSS_S_CONTINUE_NEEDED);
126
127 if (GSS_ERROR(maj_status)) {
128 if (send_tok.length>0) {
129 packet_start(SSH2_MSG_KEXGSS_CONTINUE);
130 packet_put_string(send_tok.value, send_tok.length);
131 packet_send();
132 }
133 fatal("accept_ctx died");
134 }
135
136 if (!(ret_flags & GSS_C_MUTUAL_FLAG))
137 fatal("Mutual Authentication flag wasn't set");
138
139 if (!(ret_flags & GSS_C_INTEG_FLAG))
140 fatal("Integrity flag wasn't set");
141
142 dh = dh_new_group1();
143 dh_gen_key(dh, kex->we_need * 8);
144
145 if (!dh_pub_is_valid(dh, dh_client_pub))
146 packet_disconnect("bad client public DH value");
147
148 klen = DH_size(dh);
149 kbuf = xmalloc(klen);
150 kout = DH_compute_key(kbuf, dh_client_pub, dh);
151
152 shared_secret = BN_new();
153 BN_bin2bn(kbuf, kout, shared_secret);
154 memset(kbuf, 0, klen);
155 xfree(kbuf);
156
157 /* The GSSAPI hash is identical to the Diffie Helman one */
158 hash = kex_dh_hash(
159 kex->client_version_string, kex->server_version_string,
160 buffer_ptr(&kex->peer), buffer_len(&kex->peer),
161 buffer_ptr(&kex->my), buffer_len(&kex->my),
162 NULL, 0, /* Change this if we start sending host keys */
163 dh_client_pub, dh->pub_key, shared_secret
164 );
165 BN_free(dh_client_pub);
166
167 if (kex->session_id == NULL) {
168 kex->session_id_len = 20;
169 kex->session_id = xmalloc(kex->session_id_len);
170 memcpy(kex->session_id, hash, kex->session_id_len);
171 }
172
173 gssbuf.value = hash;
174 gssbuf.length = 20; /* Hashlen appears to always be 20 */
175
176 if (GSS_ERROR(PRIVSEP(ssh_gssapi_sign(ctxt,&gssbuf,&msg_tok))))
177 fatal("Couldn't get MIC");
178
179 packet_start(SSH2_MSG_KEXGSS_COMPLETE);
180 packet_put_bignum2(dh->pub_key);
181 packet_put_string((char *)msg_tok.value,msg_tok.length);
182
183 if (send_tok.length!=0) {
184 packet_put_char(1); /* true */
185 packet_put_string((char *)send_tok.value, send_tok.length);
186 } else {
187 packet_put_char(0); /* false */
188 }
189 packet_send();
190
191 gss_release_buffer(&min_status, &send_tok);
192
193 if (gss_kex_context == NULL)
194 gss_kex_context = ctxt;
195 else
196 ssh_gssapi_delete_ctx(&ctxt);
197
198 DH_free(dh);
199
200 kex_derive_keys(kex, hash, shared_secret);
201 BN_clear_free(shared_secret);
202 kex_finish(kex);
203}
204#endif /* GSSAPI */
diff --git a/key.c b/key.c
index e41930464..db401cb12 100644
--- a/key.c
+++ b/key.c
@@ -650,6 +650,8 @@ key_type_from_name(char *name)
650 return KEY_RSA; 650 return KEY_RSA;
651 } else if (strcmp(name, "ssh-dss") == 0) { 651 } else if (strcmp(name, "ssh-dss") == 0) {
652 return KEY_DSA; 652 return KEY_DSA;
653 } else if (strcmp(name, "null") == 0) {
654 return KEY_NULL;
653 } 655 }
654 debug2("key_type_from_name: unknown key type '%s'", name); 656 debug2("key_type_from_name: unknown key type '%s'", name);
655 return KEY_UNSPEC; 657 return KEY_UNSPEC;
diff --git a/key.h b/key.h
index 50df8500b..6358e955f 100644
--- a/key.h
+++ b/key.h
@@ -34,6 +34,7 @@ enum types {
34 KEY_RSA1, 34 KEY_RSA1,
35 KEY_RSA, 35 KEY_RSA,
36 KEY_DSA, 36 KEY_DSA,
37 KEY_NULL,
37 KEY_UNSPEC 38 KEY_UNSPEC
38}; 39};
39enum fp_type { 40enum fp_type {
diff --git a/monitor.c b/monitor.c
index 301e150b3..b57b53f21 100644
--- a/monitor.c
+++ b/monitor.c
@@ -141,6 +141,7 @@ int mm_answer_gss_setup_ctx(int, Buffer *);
141int mm_answer_gss_accept_ctx(int, Buffer *); 141int mm_answer_gss_accept_ctx(int, Buffer *);
142int mm_answer_gss_userok(int, Buffer *); 142int mm_answer_gss_userok(int, Buffer *);
143int mm_answer_gss_checkmic(int, Buffer *); 143int mm_answer_gss_checkmic(int, Buffer *);
144int mm_answer_gss_sign(int, Buffer *);
144#endif 145#endif
145 146
146#ifdef SSH_AUDIT_EVENTS 147#ifdef SSH_AUDIT_EVENTS
@@ -209,11 +210,17 @@ struct mon_table mon_dispatch_proto20[] = {
209 {MONITOR_REQ_GSSSTEP, MON_ISAUTH, mm_answer_gss_accept_ctx}, 210 {MONITOR_REQ_GSSSTEP, MON_ISAUTH, mm_answer_gss_accept_ctx},
210 {MONITOR_REQ_GSSUSEROK, MON_AUTH, mm_answer_gss_userok}, 211 {MONITOR_REQ_GSSUSEROK, MON_AUTH, mm_answer_gss_userok},
211 {MONITOR_REQ_GSSCHECKMIC, MON_ISAUTH, mm_answer_gss_checkmic}, 212 {MONITOR_REQ_GSSCHECKMIC, MON_ISAUTH, mm_answer_gss_checkmic},
213 {MONITOR_REQ_GSSSIGN, MON_ONCE, mm_answer_gss_sign},
212#endif 214#endif
213 {0, 0, NULL} 215 {0, 0, NULL}
214}; 216};
215 217
216struct mon_table mon_dispatch_postauth20[] = { 218struct mon_table mon_dispatch_postauth20[] = {
219#ifdef GSSAPI
220 {MONITOR_REQ_GSSSETUP, 0, mm_answer_gss_setup_ctx},
221 {MONITOR_REQ_GSSSTEP, 0, mm_answer_gss_accept_ctx},
222 {MONITOR_REQ_GSSSIGN, 0, mm_answer_gss_sign},
223#endif
217 {MONITOR_REQ_MODULI, 0, mm_answer_moduli}, 224 {MONITOR_REQ_MODULI, 0, mm_answer_moduli},
218 {MONITOR_REQ_SIGN, 0, mm_answer_sign}, 225 {MONITOR_REQ_SIGN, 0, mm_answer_sign},
219 {MONITOR_REQ_PTY, 0, mm_answer_pty}, 226 {MONITOR_REQ_PTY, 0, mm_answer_pty},
@@ -316,6 +323,10 @@ monitor_child_preauth(Authctxt *_authctxt, struct monitor *pmonitor)
316 /* Permit requests for moduli and signatures */ 323 /* Permit requests for moduli and signatures */
317 monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); 324 monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1);
318 monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); 325 monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1);
326#ifdef GSSAPI
327 /* and for the GSSAPI key exchange */
328 monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1);
329#endif
319 } else { 330 } else {
320 mon_dispatch = mon_dispatch_proto15; 331 mon_dispatch = mon_dispatch_proto15;
321 332
@@ -389,6 +400,10 @@ monitor_child_postauth(struct monitor *pmonitor)
389 monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); 400 monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1);
390 monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); 401 monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1);
391 monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); 402 monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1);
403#ifdef GSSAPI
404 /* and for the GSSAPI key exchange */
405 monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1);
406#endif
392 } else { 407 } else {
393 mon_dispatch = mon_dispatch_postauth15; 408 mon_dispatch = mon_dispatch_postauth15;
394 monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); 409 monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1);
@@ -1623,6 +1638,9 @@ mm_get_kex(Buffer *m)
1623 kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server; 1638 kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server;
1624 kex->kex[KEX_DH_GRP14_SHA1] = kexdh_server; 1639 kex->kex[KEX_DH_GRP14_SHA1] = kexdh_server;
1625 kex->kex[KEX_DH_GEX_SHA1] = kexgex_server; 1640 kex->kex[KEX_DH_GEX_SHA1] = kexgex_server;
1641#ifdef GSSAPI
1642 kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server;
1643#endif
1626 kex->server = 1; 1644 kex->server = 1;
1627 kex->hostkey_type = buffer_get_int(m); 1645 kex->hostkey_type = buffer_get_int(m);
1628 kex->kex_type = buffer_get_int(m); 1646 kex->kex_type = buffer_get_int(m);
@@ -1865,6 +1883,7 @@ mm_answer_gss_accept_ctx(int sock, Buffer *m)
1865 monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 0); 1883 monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 0);
1866 monitor_permit(mon_dispatch, MONITOR_REQ_GSSUSEROK, 1); 1884 monitor_permit(mon_dispatch, MONITOR_REQ_GSSUSEROK, 1);
1867 monitor_permit(mon_dispatch, MONITOR_REQ_GSSCHECKMIC, 1); 1885 monitor_permit(mon_dispatch, MONITOR_REQ_GSSCHECKMIC, 1);
1886 monitor_permit(mon_dispatch, MONITOR_REQ_GSSSIGN, 1);
1868 } 1887 }
1869 return (0); 1888 return (0);
1870} 1889}
@@ -1915,4 +1934,39 @@ mm_answer_gss_userok(int sock, Buffer *m)
1915 /* Monitor loop will terminate if authenticated */ 1934 /* Monitor loop will terminate if authenticated */
1916 return (authenticated); 1935 return (authenticated);
1917} 1936}
1937
1938int
1939mm_answer_gss_sign(int socket, Buffer *m)
1940{
1941 gss_buffer_desc data, hash;
1942 OM_uint32 major, minor;
1943
1944 data.value = buffer_get_string(m, &data.length);
1945 if (data.length != 20)
1946 fatal("%s: data length incorrect: %d", __func__, data.length);
1947
1948 /* Save the session ID on the first time around */
1949 if (session_id2_len == 0) {
1950 session_id2_len = data.length;
1951 session_id2 = xmalloc(session_id2_len);
1952 memcpy(session_id2, data.value, session_id2_len);
1953 }
1954 major = ssh_gssapi_sign(gsscontext, &data, &hash);
1955
1956 xfree(data.value);
1957
1958 buffer_clear(m);
1959 buffer_put_int(m, major);
1960 buffer_put_string(m, hash.value, hash.length);
1961
1962 mm_request_send(socket, MONITOR_ANS_GSSSIGN, m);
1963
1964 gss_release_buffer(&minor, &hash);
1965
1966 /* Turn on getpwnam permissions */
1967 monitor_permit(mon_dispatch, MONITOR_REQ_PWNAM, 1);
1968
1969 return (0);
1970}
1971
1918#endif /* GSSAPI */ 1972#endif /* GSSAPI */
diff --git a/monitor.h b/monitor.h
index 13ce3e1ca..7b306b4af 100644
--- a/monitor.h
+++ b/monitor.h
@@ -53,6 +53,7 @@ enum monitor_reqtype {
53 MONITOR_REQ_GSSSTEP, MONITOR_ANS_GSSSTEP, 53 MONITOR_REQ_GSSSTEP, MONITOR_ANS_GSSSTEP,
54 MONITOR_REQ_GSSUSEROK, MONITOR_ANS_GSSUSEROK, 54 MONITOR_REQ_GSSUSEROK, MONITOR_ANS_GSSUSEROK,
55 MONITOR_REQ_GSSCHECKMIC, MONITOR_ANS_GSSCHECKMIC, 55 MONITOR_REQ_GSSCHECKMIC, MONITOR_ANS_GSSCHECKMIC,
56 MONITOR_REQ_GSSSIGN, MONITOR_ANS_GSSSIGN,
56 MONITOR_REQ_PAM_START, 57 MONITOR_REQ_PAM_START,
57 MONITOR_REQ_PAM_ACCOUNT, MONITOR_ANS_PAM_ACCOUNT, 58 MONITOR_REQ_PAM_ACCOUNT, MONITOR_ANS_PAM_ACCOUNT,
58 MONITOR_REQ_PAM_INIT_CTX, MONITOR_ANS_PAM_INIT_CTX, 59 MONITOR_REQ_PAM_INIT_CTX, MONITOR_ANS_PAM_INIT_CTX,
diff --git a/monitor_wrap.c b/monitor_wrap.c
index e1b6512b4..482ff5bc3 100644
--- a/monitor_wrap.c
+++ b/monitor_wrap.c
@@ -1217,4 +1217,25 @@ mm_ssh_gssapi_userok(char *user)
1217 debug3("%s: user %sauthenticated",__func__, authenticated ? "" : "not "); 1217 debug3("%s: user %sauthenticated",__func__, authenticated ? "" : "not ");
1218 return (authenticated); 1218 return (authenticated);
1219} 1219}
1220
1221OM_uint32
1222mm_ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_desc *data, gss_buffer_desc *hash)
1223{
1224 Buffer m;
1225 OM_uint32 major;
1226
1227 buffer_init(&m);
1228 buffer_put_string(&m, data->value, data->length);
1229
1230 mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSSIGN, &m);
1231 mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSSIGN, &m);
1232
1233 major = buffer_get_int(&m);
1234 hash->value = buffer_get_string(&m, &hash->length);
1235
1236 buffer_free(&m);
1237
1238 return(major);
1239}
1240
1220#endif /* GSSAPI */ 1241#endif /* GSSAPI */
diff --git a/monitor_wrap.h b/monitor_wrap.h
index 310b42513..871eabb9d 100644
--- a/monitor_wrap.h
+++ b/monitor_wrap.h
@@ -63,6 +63,7 @@ OM_uint32 mm_ssh_gssapi_accept_ctx(Gssctxt *,
63 gss_buffer_desc *, gss_buffer_desc *, OM_uint32 *); 63 gss_buffer_desc *, gss_buffer_desc *, OM_uint32 *);
64int mm_ssh_gssapi_userok(char *user); 64int mm_ssh_gssapi_userok(char *user);
65OM_uint32 mm_ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t); 65OM_uint32 mm_ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t);
66OM_uint32 mm_ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t);
66#endif 67#endif
67 68
68#ifdef USE_PAM 69#ifdef USE_PAM
diff --git a/ssh-gss.h b/ssh-gss.h
index 52fb49a6f..74ce6f8bc 100644
--- a/ssh-gss.h
+++ b/ssh-gss.h
@@ -62,6 +62,13 @@
62 62
63#define SSH_GSS_OIDTYPE 0x06 63#define SSH_GSS_OIDTYPE 0x06
64 64
65#define SSH2_MSG_KEXGSS_INIT 30
66#define SSH2_MSG_KEXGSS_CONTINUE 31
67#define SSH2_MSG_KEXGSS_COMPLETE 32
68#define SSH2_MSG_KEXGSS_HOSTKEY 33
69#define SSH2_MSG_KEXGSS_ERROR 34
70#define KEX_GSS_SHA1 "gss-group1-sha1-"
71
65typedef struct { 72typedef struct {
66 char *filename; 73 char *filename;
67 char *envvar; 74 char *envvar;
@@ -99,6 +106,7 @@ typedef struct {
99} Gssctxt; 106} Gssctxt;
100 107
101extern ssh_gssapi_mech *supported_mechs[]; 108extern ssh_gssapi_mech *supported_mechs[];
109extern Gssctxt *gss_kex_context;
102 110
103int ssh_gssapi_check_oid(Gssctxt *, void *, size_t); 111int ssh_gssapi_check_oid(Gssctxt *, void *, size_t);
104void ssh_gssapi_set_oid_data(Gssctxt *, void *, size_t); 112void ssh_gssapi_set_oid_data(Gssctxt *, void *, size_t);
@@ -121,7 +129,13 @@ OM_uint32 ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t);
121OM_uint32 ssh_gssapi_server_ctx(Gssctxt **, gss_OID); 129OM_uint32 ssh_gssapi_server_ctx(Gssctxt **, gss_OID);
122void ssh_gssapi_buildmic(Buffer *, const char *, const char *, const char *); 130void ssh_gssapi_buildmic(Buffer *, const char *, const char *, const char *);
123 131
124/* In the server */ 132typedef int ssh_gssapi_check_fn(gss_OID, void *);
133char *ssh_gssapi_client_mechanisms(char *host);
134char *ssh_gssapi_kex_mechs(gss_OID_set, ssh_gssapi_check_fn *, void *);
135int ssh_gssapi_check_mechanism(gss_OID, void *);
136gss_OID ssh_gssapi_id_kex(Gssctxt *, char *);
137
138int ssh_gssapi_server_check_mech(gss_OID, void *);
125int ssh_gssapi_userok(char *name); 139int ssh_gssapi_userok(char *name);
126OM_uint32 ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t); 140OM_uint32 ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t);
127void ssh_gssapi_do_child(char ***, u_int *); 141void ssh_gssapi_do_child(char ***, u_int *);
diff --git a/sshconnect2.c b/sshconnect2.c
index 68d56d020..b69602c0c 100644
--- a/sshconnect2.c
+++ b/sshconnect2.c
@@ -84,9 +84,26 @@ ssh_kex2(char *host, struct sockaddr *hostaddr)
84{ 84{
85 Kex *kex; 85 Kex *kex;
86 86
87#ifdef GSSAPI
88 char *orig, *gss;
89 int len;
90#endif
91
87 xxx_host = host; 92 xxx_host = host;
88 xxx_hostaddr = hostaddr; 93 xxx_hostaddr = hostaddr;
89 94
95#ifdef GSSAPI
96 orig = myproposal[PROPOSAL_KEX_ALGS];
97 gss = ssh_gssapi_client_mechanisms(get_canonical_hostname(1));
98 debug("Offering GSSAPI proposal: %s",gss);
99 if (gss) {
100 len = strlen(orig) + strlen(gss) + 2;
101 myproposal[PROPOSAL_KEX_ALGS] = xmalloc(len);
102 snprintf(myproposal[PROPOSAL_KEX_ALGS], len, "%s,%s", gss,
103 orig);
104 }
105#endif
106
90 if (options.ciphers == (char *)-1) { 107 if (options.ciphers == (char *)-1) {
91 logit("No valid ciphers for protocol version 2 given, using defaults."); 108 logit("No valid ciphers for protocol version 2 given, using defaults.");
92 options.ciphers = NULL; 109 options.ciphers = NULL;
@@ -114,6 +131,16 @@ ssh_kex2(char *host, struct sockaddr *hostaddr)
114 myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = 131 myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] =
115 options.hostkeyalgorithms; 132 options.hostkeyalgorithms;
116 133
134#ifdef GSSAPI
135 if (gss) {
136 orig = myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS];
137 len = strlen(orig) + sizeof(",null");
138 myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = xmalloc(len);
139 snprintf(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS], len,
140 "%s,null", orig);
141 }
142#endif
143
117 if (options.rekey_limit) 144 if (options.rekey_limit)
118 packet_set_rekey_limit(options.rekey_limit); 145 packet_set_rekey_limit(options.rekey_limit);
119 146
@@ -122,10 +149,17 @@ ssh_kex2(char *host, struct sockaddr *hostaddr)
122 kex->kex[KEX_DH_GRP1_SHA1] = kexdh_client; 149 kex->kex[KEX_DH_GRP1_SHA1] = kexdh_client;
123 kex->kex[KEX_DH_GRP14_SHA1] = kexdh_client; 150 kex->kex[KEX_DH_GRP14_SHA1] = kexdh_client;
124 kex->kex[KEX_DH_GEX_SHA1] = kexgex_client; 151 kex->kex[KEX_DH_GEX_SHA1] = kexgex_client;
152#ifdef GSSAPI
153 kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_client;
154#endif
125 kex->client_version_string=client_version_string; 155 kex->client_version_string=client_version_string;
126 kex->server_version_string=server_version_string; 156 kex->server_version_string=server_version_string;
127 kex->verify_host_key=&verify_host_key_callback; 157 kex->verify_host_key=&verify_host_key_callback;
128 158
159#ifdef GSSAPI
160 kex->gss_deleg_creds = options.gss_deleg_creds;
161#endif
162
129 xxx_kex = kex; 163 xxx_kex = kex;
130 164
131 dispatch_run(DISPATCH_BLOCK, &kex->done, kex); 165 dispatch_run(DISPATCH_BLOCK, &kex->done, kex);
@@ -208,6 +242,7 @@ void input_gssapi_token(int type, u_int32_t, void *);
208void input_gssapi_hash(int type, u_int32_t, void *); 242void input_gssapi_hash(int type, u_int32_t, void *);
209void input_gssapi_error(int, u_int32_t, void *); 243void input_gssapi_error(int, u_int32_t, void *);
210void input_gssapi_errtok(int, u_int32_t, void *); 244void input_gssapi_errtok(int, u_int32_t, void *);
245int userauth_gsskeyx(Authctxt *authctxt);
211#endif 246#endif
212 247
213void userauth(Authctxt *, char *); 248void userauth(Authctxt *, char *);
@@ -223,6 +258,10 @@ static char *authmethods_get(void);
223 258
224Authmethod authmethods[] = { 259Authmethod authmethods[] = {
225#ifdef GSSAPI 260#ifdef GSSAPI
261 {"gssapi-keyx",
262 userauth_gsskeyx,
263 &options.gss_authentication,
264 NULL},
226 {"gssapi-with-mic", 265 {"gssapi-with-mic",
227 userauth_gssapi, 266 userauth_gssapi,
228 &options.gss_authentication, 267 &options.gss_authentication,
@@ -704,6 +743,47 @@ input_gssapi_error(int type, u_int32_t plen, void *ctxt)
704 xfree(msg); 743 xfree(msg);
705 xfree(lang); 744 xfree(lang);
706} 745}
746
747int
748userauth_gsskeyx(Authctxt *authctxt)
749{
750 Buffer b;
751 gss_buffer_desc gssbuf, mic;
752 OM_uint32 ms;
753
754 static int attempt = 0;
755 if (attempt++ >= 1)
756 return (0);
757
758 if (gss_kex_context == NULL) {
759 debug("No valid Key exchange context");
760 return (0);
761 }
762
763 ssh_gssapi_buildmic(&b, authctxt->server_user, authctxt->service,
764 "gssapi-keyex");
765
766 gssbuf.value = buffer_ptr(&b);
767 gssbuf.length = buffer_len(&b);
768
769 if (GSS_ERROR(ssh_gssapi_sign(gss_kex_context, &gssbuf, &mic))) {
770 buffer_free(&b);
771 return (0);
772 }
773
774 packet_start(SSH2_MSG_USERAUTH_REQUEST);
775 packet_put_cstring(authctxt->server_user);
776 packet_put_cstring(authctxt->service);
777 packet_put_cstring(authctxt->method->name);
778 packet_put_string(mic.value, mic.length);
779 packet_send();
780
781 buffer_free(&b);
782 gss_release_buffer(&ms, &mic);
783
784 return (1);
785}
786
707#endif /* GSSAPI */ 787#endif /* GSSAPI */
708 788
709int 789int
diff --git a/sshd.c b/sshd.c
index 11d618d11..51b476778 100644
--- a/sshd.c
+++ b/sshd.c
@@ -1110,10 +1110,12 @@ main(int ac, char **av)
1110 logit("Disabling protocol version 1. Could not load host key"); 1110 logit("Disabling protocol version 1. Could not load host key");
1111 options.protocol &= ~SSH_PROTO_1; 1111 options.protocol &= ~SSH_PROTO_1;
1112 } 1112 }
1113#ifndef GSSAPI
1113 if ((options.protocol & SSH_PROTO_2) && !sensitive_data.have_ssh2_key) { 1114 if ((options.protocol & SSH_PROTO_2) && !sensitive_data.have_ssh2_key) {
1114 logit("Disabling protocol version 2. Could not load host key"); 1115 logit("Disabling protocol version 2. Could not load host key");
1115 options.protocol &= ~SSH_PROTO_2; 1116 options.protocol &= ~SSH_PROTO_2;
1116 } 1117 }
1118#endif
1117 if (!(options.protocol & (SSH_PROTO_1|SSH_PROTO_2))) { 1119 if (!(options.protocol & (SSH_PROTO_1|SSH_PROTO_2))) {
1118 logit("sshd: no hostkeys available -- exiting."); 1120 logit("sshd: no hostkeys available -- exiting.");
1119 exit(1); 1121 exit(1);
@@ -1990,13 +1992,59 @@ do_ssh2_kex(void)
1990 myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = list_hostkey_types(); 1992 myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = list_hostkey_types();
1991 1993
1992 /* start key exchange */ 1994 /* start key exchange */
1993 kex = kex_setup(myproposal); 1995
1994 kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server; 1996#ifdef GSSAPI
1997 {
1998 char *orig;
1999 char *gss = NULL;
2000 char *newstr = NULL;
2001 orig = myproposal[PROPOSAL_KEX_ALGS];
2002
2003 /*
2004 * If we don't have a host key, then there's no point advertising
2005 * the other key exchange algorithms
2006 */
2007
2008 if (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]) == 0)
2009 orig = NULL;
2010
2011 gss = ssh_gssapi_server_mechanisms();
2012
2013 if (gss && orig) {
2014 int len = strlen(orig) + strlen(gss) + 2;
2015 newstr = xmalloc(len);
2016 snprintf(newstr, len, "%s,%s", gss, orig);
2017 } else if (gss) {
2018 newstr = gss;
2019 } else if (orig) {
2020 newstr = orig;
2021 }
2022 /*
2023 * If we've got GSSAPI mechanisms, then we've got the 'null' host
2024 * key alg, but we can't tell people about it unless its the only
2025 * host key algorithm we support
2026 */
2027 if (gss && (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS])) == 0)
2028 myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = "null";
2029
2030 if (newstr)
2031 myproposal[PROPOSAL_KEX_ALGS] = newstr;
2032 else
2033 fatal("No supported key exchange algorithms");
2034 }
2035#endif
2036
2037 /* start key exchange */
2038 kex = kex_setup(myproposal);
2039 kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server;
1995 kex->kex[KEX_DH_GRP14_SHA1] = kexdh_server; 2040 kex->kex[KEX_DH_GRP14_SHA1] = kexdh_server;
1996 kex->kex[KEX_DH_GEX_SHA1] = kexgex_server; 2041 kex->kex[KEX_DH_GEX_SHA1] = kexgex_server;
1997 kex->server = 1; 2042#ifdef GSSAPI
1998 kex->client_version_string=client_version_string; 2043 kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server;
1999 kex->server_version_string=server_version_string; 2044#endif
2045 kex->server = 1;
2046 kex->client_version_string=client_version_string;
2047 kex->server_version_string=server_version_string;
2000 kex->load_host_key=&get_hostkey_by_type; 2048 kex->load_host_key=&get_hostkey_by_type;
2001 kex->host_key_index=&get_hostkey_index; 2049 kex->host_key_index=&get_hostkey_index;
2002 2050