diff options
-rw-r--r-- | Makefile.in | 4 | ||||
-rw-r--r-- | auth2-gss.c | 39 | ||||
-rw-r--r-- | auth2.c | 2 | ||||
-rw-r--r-- | gss-genr.c | 156 | ||||
-rw-r--r-- | gss-serv.c | 32 | ||||
-rw-r--r-- | kex.c | 9 | ||||
-rw-r--r-- | kex.h | 9 | ||||
-rw-r--r-- | kexgssc.c | 242 | ||||
-rw-r--r-- | kexgsss.c | 204 | ||||
-rw-r--r-- | key.c | 2 | ||||
-rw-r--r-- | key.h | 1 | ||||
-rw-r--r-- | monitor.c | 54 | ||||
-rw-r--r-- | monitor.h | 1 | ||||
-rw-r--r-- | monitor_wrap.c | 21 | ||||
-rw-r--r-- | monitor_wrap.h | 1 | ||||
-rw-r--r-- | ssh-gss.h | 16 | ||||
-rw-r--r-- | sshconnect2.c | 80 | ||||
-rw-r--r-- | sshd.c | 58 |
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 | ||
76 | SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \ | 76 | SSHOBJS= 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); | |||
47 | static void input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt); | 47 | static void input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt); |
48 | static void input_gssapi_errtok(int, u_int32_t, void *); | 48 | static void input_gssapi_errtok(int, u_int32_t, void *); |
49 | 49 | ||
50 | /* | ||
51 | * The 'gssapi_keyex' userauth mechanism. | ||
52 | */ | ||
53 | static int | ||
54 | userauth_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 | ||
322 | Authmethod method_gsskeyex = { | ||
323 | "gssapi-keyx", | ||
324 | userauth_gsskeyex, | ||
325 | &options.gss_authentication | ||
326 | }; | ||
327 | |||
289 | Authmethod method_gssapi = { | 328 | Authmethod method_gssapi = { |
290 | "gssapi-with-mic", | 329 | "gssapi-with-mic", |
291 | userauth_gssapi, | 330 | userauth_gssapi, |
@@ -55,6 +55,7 @@ extern Authmethod method_passwd; | |||
55 | extern Authmethod method_kbdint; | 55 | extern Authmethod method_kbdint; |
56 | extern Authmethod method_hostbased; | 56 | extern Authmethod method_hostbased; |
57 | #ifdef GSSAPI | 57 | #ifdef GSSAPI |
58 | extern Authmethod method_gsskeyex; | ||
58 | extern Authmethod method_gssapi; | 59 | extern 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 | ||
40 | extern u_char *session_id2; | 41 | extern u_char *session_id2; |
41 | extern u_int session_id2_len; | 42 | extern u_int session_id2_len; |
42 | 43 | ||
44 | typedef 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 | |||
54 | Gssctxt *gss_kex_context = NULL; | ||
55 | |||
56 | static 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 | |||
66 | char * | ||
67 | ssh_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 | |||
77 | char * | ||
78 | ssh_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 | |||
148 | gss_OID | ||
149 | ssh_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 */ |
44 | int | 169 | int |
45 | ssh_gssapi_check_oid(Gssctxt *ctx, void *data, size_t len) | 170 | ssh_gssapi_check_oid(Gssctxt *ctx, void *data, size_t len) |
@@ -250,6 +375,9 @@ ssh_gssapi_acquire_cred(Gssctxt *ctx) | |||
250 | OM_uint32 | 375 | OM_uint32 |
251 | ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash) | 376 | ssh_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 */ | ||
389 | OM_uint32 | ||
390 | ssh_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 | |||
260 | void | 401 | void |
261 | ssh_gssapi_buildmic(Buffer *b, const char *user, const char *service, | 402 | ssh_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 | ||
422 | int | ||
423 | ssh_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 */ |
65 | char * | ||
66 | ssh_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 */ | ||
75 | int | ||
76 | ssh_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 */ | ||
65 | void | 87 | void |
66 | ssh_gssapi_supported_oids(gss_OID_set *oidset) | 88 | ssh_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 */ | ||
291 | OM_uint32 | ||
292 | ssh_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 |
@@ -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 | } |
@@ -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 *); | |||
132 | void kexgex_client(Kex *); | 136 | void kexgex_client(Kex *); |
133 | void kexgex_server(Kex *); | 137 | void kexgex_server(Kex *); |
134 | 138 | ||
139 | #ifdef GSSAPI | ||
140 | void kexgss_client(Kex *); | ||
141 | void kexgss_server(Kex *); | ||
142 | #endif | ||
143 | |||
135 | u_char * | 144 | u_char * |
136 | kex_dh_hash(char *, char *, char *, int, char *, int, u_char *, int, | 145 | kex_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 | |||
43 | void | ||
44 | kexgss_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 | |||
43 | void | ||
44 | kexgss_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 */ | ||
@@ -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; |
@@ -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 | }; |
39 | enum fp_type { | 40 | enum fp_type { |
@@ -141,6 +141,7 @@ int mm_answer_gss_setup_ctx(int, Buffer *); | |||
141 | int mm_answer_gss_accept_ctx(int, Buffer *); | 141 | int mm_answer_gss_accept_ctx(int, Buffer *); |
142 | int mm_answer_gss_userok(int, Buffer *); | 142 | int mm_answer_gss_userok(int, Buffer *); |
143 | int mm_answer_gss_checkmic(int, Buffer *); | 143 | int mm_answer_gss_checkmic(int, Buffer *); |
144 | int 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 | ||
216 | struct mon_table mon_dispatch_postauth20[] = { | 218 | struct 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 | |||
1938 | int | ||
1939 | mm_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 */ |
@@ -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 | |||
1221 | OM_uint32 | ||
1222 | mm_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 *); |
64 | int mm_ssh_gssapi_userok(char *user); | 64 | int mm_ssh_gssapi_userok(char *user); |
65 | OM_uint32 mm_ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t); | 65 | OM_uint32 mm_ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t); |
66 | OM_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 |
@@ -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 | |||
65 | typedef struct { | 72 | typedef 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 | ||
101 | extern ssh_gssapi_mech *supported_mechs[]; | 108 | extern ssh_gssapi_mech *supported_mechs[]; |
109 | extern Gssctxt *gss_kex_context; | ||
102 | 110 | ||
103 | int ssh_gssapi_check_oid(Gssctxt *, void *, size_t); | 111 | int ssh_gssapi_check_oid(Gssctxt *, void *, size_t); |
104 | void ssh_gssapi_set_oid_data(Gssctxt *, void *, size_t); | 112 | void 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); | |||
121 | OM_uint32 ssh_gssapi_server_ctx(Gssctxt **, gss_OID); | 129 | OM_uint32 ssh_gssapi_server_ctx(Gssctxt **, gss_OID); |
122 | void ssh_gssapi_buildmic(Buffer *, const char *, const char *, const char *); | 130 | void ssh_gssapi_buildmic(Buffer *, const char *, const char *, const char *); |
123 | 131 | ||
124 | /* In the server */ | 132 | typedef int ssh_gssapi_check_fn(gss_OID, void *); |
133 | char *ssh_gssapi_client_mechanisms(char *host); | ||
134 | char *ssh_gssapi_kex_mechs(gss_OID_set, ssh_gssapi_check_fn *, void *); | ||
135 | int ssh_gssapi_check_mechanism(gss_OID, void *); | ||
136 | gss_OID ssh_gssapi_id_kex(Gssctxt *, char *); | ||
137 | |||
138 | int ssh_gssapi_server_check_mech(gss_OID, void *); | ||
125 | int ssh_gssapi_userok(char *name); | 139 | int ssh_gssapi_userok(char *name); |
126 | OM_uint32 ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t); | 140 | OM_uint32 ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t); |
127 | void ssh_gssapi_do_child(char ***, u_int *); | 141 | void 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 *); | |||
208 | void input_gssapi_hash(int type, u_int32_t, void *); | 242 | void input_gssapi_hash(int type, u_int32_t, void *); |
209 | void input_gssapi_error(int, u_int32_t, void *); | 243 | void input_gssapi_error(int, u_int32_t, void *); |
210 | void input_gssapi_errtok(int, u_int32_t, void *); | 244 | void input_gssapi_errtok(int, u_int32_t, void *); |
245 | int userauth_gsskeyx(Authctxt *authctxt); | ||
211 | #endif | 246 | #endif |
212 | 247 | ||
213 | void userauth(Authctxt *, char *); | 248 | void userauth(Authctxt *, char *); |
@@ -223,6 +258,10 @@ static char *authmethods_get(void); | |||
223 | 258 | ||
224 | Authmethod authmethods[] = { | 259 | Authmethod 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 | |||
747 | int | ||
748 | userauth_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 | ||
709 | int | 789 | int |
@@ -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 | ||