|
1 # |
|
2 # GSS-API key exchange support |
|
3 # |
|
4 # Based on https://github.com/SimonWilkinson/gss-openssh/commit/ffae842 |
|
5 # Updated to apply to OpenSSH 6.5. |
|
6 # Default value for GSSAPIKeyExchange changed to yes to match SunSSH behavior. |
|
7 # New files kexgssc.c and kexgsss.c moved to ../sources/ and made cstyle clean. |
|
8 # |
|
9 # Upstream rejected GSS-API key exchange several times before. |
|
10 # |
|
11 diff -pur old/Makefile.in new/Makefile.in |
|
12 --- old/Makefile.in 2015-12-10 14:51:47.781146370 -0800 |
|
13 +++ new/Makefile.in 2015-12-10 14:48:21.907121340 -0800 |
|
14 @@ -85,6 +85,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \ |
|
15 atomicio.o key.o dispatch.o mac.o uidswap.o uuencode.o misc.o \ |
|
16 monitor_fdpass.o rijndael.o ssh-dss.o ssh-ecdsa.o ssh-rsa.o dh.o \ |
|
17 msg.o progressmeter.o dns.o entropy.o gss-genr.o umac.o umac128.o \ |
|
18 + kexgssc.o \ |
|
19 ssh-pkcs11.o smult_curve25519_ref.o \ |
|
20 poly1305.o chacha.o cipher-chachapoly.o \ |
|
21 ssh-ed25519.o digest-openssl.o digest-libc.o hmac.o \ |
|
22 @@ -105,7 +106,7 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passw |
|
23 auth-skey.o auth-bsdauth.o auth2-hostbased.o auth2-kbdint.o \ |
|
24 auth2-none.o auth2-passwd.o auth2-pubkey.o \ |
|
25 monitor_mm.o monitor.o monitor_wrap.o auth-krb5.o \ |
|
26 - auth2-gss.o gss-serv.o gss-serv-krb5.o \ |
|
27 + auth2-gss.o gss-serv.o gss-serv-krb5.o kexgsss.o \ |
|
28 loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \ |
|
29 sftp-server.o sftp-common.o \ |
|
30 roaming_common.o roaming_serv.o \ |
|
31 diff -pur old/auth2-gss.c new/auth2-gss.c |
|
32 --- old/auth2-gss.c |
|
33 +++ new/auth2-gss.c |
|
34 @@ -1,7 +1,7 @@ |
|
35 /* $OpenBSD: auth2-gss.c,v 1.22 2015/01/19 20:07:45 markus Exp $ */ |
|
36 |
|
37 /* |
|
38 - * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. |
|
39 + * Copyright (c) 2001-2007 Simon Wilkinson. All rights reserved. |
|
40 * |
|
41 * Redistribution and use in source and binary forms, with or without |
|
42 * modification, are permitted provided that the following conditions |
|
43 @@ -53,6 +53,39 @@ static int input_gssapi_mic(int type, u_ |
|
44 static int input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt); |
|
45 static int input_gssapi_errtok(int, u_int32_t, void *); |
|
46 |
|
47 +/* |
|
48 + * The 'gssapi_keyex' userauth mechanism. |
|
49 + */ |
|
50 +static int |
|
51 +userauth_gsskeyex(Authctxt *authctxt) |
|
52 +{ |
|
53 + int authenticated = 0; |
|
54 + Buffer b; |
|
55 + gss_buffer_desc mic, gssbuf; |
|
56 + u_int len; |
|
57 + |
|
58 + mic.value = packet_get_string(&len); |
|
59 + mic.length = len; |
|
60 + |
|
61 + packet_check_eom(); |
|
62 + |
|
63 + ssh_gssapi_buildmic(&b, authctxt->user, authctxt->service, |
|
64 + "gssapi-keyex"); |
|
65 + |
|
66 + gssbuf.value = buffer_ptr(&b); |
|
67 + gssbuf.length = buffer_len(&b); |
|
68 + |
|
69 + /* gss_kex_context is NULL with privsep, so we can't check it here */ |
|
70 + if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gss_kex_context, |
|
71 + &gssbuf, &mic)))) |
|
72 + authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user)); |
|
73 + |
|
74 + buffer_free(&b); |
|
75 + free(mic.value); |
|
76 + |
|
77 + return (authenticated); |
|
78 +} |
|
79 + |
|
80 /* |
|
81 * We only support those mechanisms that we know about (ie ones that we know |
|
82 * how to check local user kuserok and the like) |
|
83 @@ -290,6 +323,12 @@ input_gssapi_mic(int type, u_int32_t ple |
|
84 return 0; |
|
85 } |
|
86 |
|
87 +Authmethod method_gsskeyex = { |
|
88 + "gssapi-keyex", |
|
89 + userauth_gsskeyex, |
|
90 + &options.gss_authentication |
|
91 +}; |
|
92 + |
|
93 Authmethod method_gssapi = { |
|
94 "gssapi-with-mic", |
|
95 userauth_gssapi, |
|
96 diff -pur old/auth2.c new/auth2.c |
|
97 --- old/auth2.c |
|
98 +++ new/auth2.c |
|
99 @@ -70,6 +70,7 @@ extern Authmethod method_passwd; |
|
100 extern Authmethod method_kbdint; |
|
101 extern Authmethod method_hostbased; |
|
102 #ifdef GSSAPI |
|
103 +extern Authmethod method_gsskeyex; |
|
104 extern Authmethod method_gssapi; |
|
105 #endif |
|
106 |
|
107 @@ -77,6 +78,7 @@ Authmethod *authmethods[] = { |
|
108 &method_none, |
|
109 &method_pubkey, |
|
110 #ifdef GSSAPI |
|
111 + &method_gsskeyex, |
|
112 &method_gssapi, |
|
113 #endif |
|
114 &method_passwd, |
|
115 diff -pur old/configure new/configure |
|
116 --- old/configure |
|
117 +++ new/configure |
|
118 @@ -10944,8 +10944,10 @@ fi |
|
119 |
|
120 fi |
|
121 |
|
122 - $as_echo "#define USE_GSS_STORE_CRED 1" >>confdefs.h |
|
123 - $as_echo "#define GSSAPI_STORECREDS_NEEDS_RUID 1" >>confdefs.h |
|
124 +cat >>confdefs.h <<\_ACEOF |
|
125 +#define USE_GSS_STORE_CRED 1 |
|
126 +#define GSSAPI_STORECREDS_NEEDS_RUID 1 |
|
127 +_ACEOF |
|
128 |
|
129 TEST_SHELL=$SHELL # let configure find us a capable shell |
|
130 ;; |
|
131 diff -pur old/gss-genr.c new/gss-genr.c |
|
132 --- old/gss-genr.c |
|
133 +++ new/gss-genr.c |
|
134 @@ -1,7 +1,7 @@ |
|
135 /* $OpenBSD: gss-genr.c,v 1.23 2015/01/20 23:14:00 deraadt Exp $ */ |
|
136 |
|
137 /* |
|
138 - * Copyright (c) 2001-2007 Simon Wilkinson. All rights reserved. |
|
139 + * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved. |
|
140 * |
|
141 * Redistribution and use in source and binary forms, with or without |
|
142 * modification, are permitted provided that the following conditions |
|
143 @@ -41,12 +41,167 @@ |
|
144 #include "buffer.h" |
|
145 #include "log.h" |
|
146 #include "ssh2.h" |
|
147 +#include "cipher.h" |
|
148 +#include "key.h" |
|
149 +#include "kex.h" |
|
150 +#include <openssl/evp.h> |
|
151 |
|
152 #include "ssh-gss.h" |
|
153 |
|
154 extern u_char *session_id2; |
|
155 extern u_int session_id2_len; |
|
156 |
|
157 +typedef struct { |
|
158 + char *encoded; |
|
159 + gss_OID oid; |
|
160 +} ssh_gss_kex_mapping; |
|
161 + |
|
162 +/* |
|
163 + * XXX - It would be nice to find a more elegant way of handling the |
|
164 + * XXX passing of the key exchange context to the userauth routines |
|
165 + */ |
|
166 + |
|
167 +Gssctxt *gss_kex_context = NULL; |
|
168 + |
|
169 +static ssh_gss_kex_mapping *gss_enc2oid = NULL; |
|
170 + |
|
171 +int |
|
172 +ssh_gssapi_oid_table_ok() { |
|
173 + return (gss_enc2oid != NULL); |
|
174 +} |
|
175 + |
|
176 +/* |
|
177 + * Return a list of the gss-group1-sha1 mechanisms supported by this program |
|
178 + * |
|
179 + * We test mechanisms to ensure that we can use them, to avoid starting |
|
180 + * a key exchange with a bad mechanism |
|
181 + */ |
|
182 + |
|
183 +char * |
|
184 +ssh_gssapi_client_mechanisms(const char *host) { |
|
185 + gss_OID_set gss_supported; |
|
186 + OM_uint32 min_status; |
|
187 + |
|
188 + if (GSS_ERROR(gss_indicate_mechs(&min_status, &gss_supported))) |
|
189 + return NULL; |
|
190 + |
|
191 + return(ssh_gssapi_kex_mechs(gss_supported, ssh_gssapi_check_mechanism, |
|
192 + host)); |
|
193 +} |
|
194 + |
|
195 +char * |
|
196 +ssh_gssapi_kex_mechs(gss_OID_set gss_supported, ssh_gssapi_check_fn *check, |
|
197 + const char *data) { |
|
198 + Buffer buf; |
|
199 + size_t i; |
|
200 + int oidpos, enclen; |
|
201 + char *mechs, *encoded; |
|
202 + u_char digest[EVP_MAX_MD_SIZE]; |
|
203 + char deroid[2]; |
|
204 + const EVP_MD *evp_md = EVP_md5(); |
|
205 + EVP_MD_CTX md; |
|
206 + |
|
207 + if (gss_enc2oid != NULL) { |
|
208 + for (i = 0; gss_enc2oid[i].encoded != NULL; i++) |
|
209 + free(gss_enc2oid[i].encoded); |
|
210 + free(gss_enc2oid); |
|
211 + } |
|
212 + |
|
213 + gss_enc2oid = xmalloc(sizeof(ssh_gss_kex_mapping) * |
|
214 + (gss_supported->count + 1)); |
|
215 + |
|
216 + buffer_init(&buf); |
|
217 + |
|
218 + oidpos = 0; |
|
219 + for (i = 0; i < gss_supported->count; i++) { |
|
220 + if (gss_supported->elements[i].length < 128 && |
|
221 + (*check)(NULL, &(gss_supported->elements[i]), data)) { |
|
222 + |
|
223 + deroid[0] = SSH_GSS_OIDTYPE; |
|
224 + deroid[1] = gss_supported->elements[i].length; |
|
225 + |
|
226 + EVP_DigestInit(&md, evp_md); |
|
227 + EVP_DigestUpdate(&md, deroid, 2); |
|
228 + EVP_DigestUpdate(&md, |
|
229 + gss_supported->elements[i].elements, |
|
230 + gss_supported->elements[i].length); |
|
231 + EVP_DigestFinal(&md, digest, NULL); |
|
232 + |
|
233 + encoded = xmalloc(EVP_MD_size(evp_md) * 2); |
|
234 + enclen = __b64_ntop(digest, EVP_MD_size(evp_md), |
|
235 + encoded, EVP_MD_size(evp_md) * 2); |
|
236 + |
|
237 + if (oidpos != 0) |
|
238 + buffer_put_char(&buf, ','); |
|
239 + |
|
240 + buffer_append(&buf, KEX_GSS_GEX_SHA1_ID, |
|
241 + sizeof(KEX_GSS_GEX_SHA1_ID) - 1); |
|
242 + buffer_append(&buf, encoded, enclen); |
|
243 + buffer_put_char(&buf, ','); |
|
244 + buffer_append(&buf, KEX_GSS_GRP1_SHA1_ID, |
|
245 + sizeof(KEX_GSS_GRP1_SHA1_ID) - 1); |
|
246 + buffer_append(&buf, encoded, enclen); |
|
247 + buffer_put_char(&buf, ','); |
|
248 + buffer_append(&buf, KEX_GSS_GRP14_SHA1_ID, |
|
249 + sizeof(KEX_GSS_GRP14_SHA1_ID) - 1); |
|
250 + buffer_append(&buf, encoded, enclen); |
|
251 + |
|
252 + gss_enc2oid[oidpos].oid = &(gss_supported->elements[i]); |
|
253 + gss_enc2oid[oidpos].encoded = encoded; |
|
254 + oidpos++; |
|
255 + } |
|
256 + } |
|
257 + gss_enc2oid[oidpos].oid = NULL; |
|
258 + gss_enc2oid[oidpos].encoded = NULL; |
|
259 + |
|
260 + buffer_put_char(&buf, '\0'); |
|
261 + |
|
262 + mechs = xmalloc(buffer_len(&buf)); |
|
263 + buffer_get(&buf, mechs, buffer_len(&buf)); |
|
264 + buffer_free(&buf); |
|
265 + |
|
266 + if (strlen(mechs) == 0) { |
|
267 + free(mechs); |
|
268 + mechs = NULL; |
|
269 + } |
|
270 + |
|
271 + return (mechs); |
|
272 +} |
|
273 + |
|
274 +gss_OID |
|
275 +ssh_gssapi_id_kex(Gssctxt *ctx, char *name, int kex_type) { |
|
276 + int i = 0; |
|
277 + |
|
278 + switch (kex_type) { |
|
279 + case KEX_GSS_GRP1_SHA1: |
|
280 + if (strlen(name) < sizeof(KEX_GSS_GRP1_SHA1_ID)) |
|
281 + return GSS_C_NO_OID; |
|
282 + name += sizeof(KEX_GSS_GRP1_SHA1_ID) - 1; |
|
283 + break; |
|
284 + case KEX_GSS_GRP14_SHA1: |
|
285 + if (strlen(name) < sizeof(KEX_GSS_GRP14_SHA1_ID)) |
|
286 + return GSS_C_NO_OID; |
|
287 + name += sizeof(KEX_GSS_GRP14_SHA1_ID) - 1; |
|
288 + break; |
|
289 + case KEX_GSS_GEX_SHA1: |
|
290 + if (strlen(name) < sizeof(KEX_GSS_GEX_SHA1_ID)) |
|
291 + return GSS_C_NO_OID; |
|
292 + name += sizeof(KEX_GSS_GEX_SHA1_ID) - 1; |
|
293 + break; |
|
294 + default: |
|
295 + return GSS_C_NO_OID; |
|
296 + } |
|
297 + |
|
298 + while (gss_enc2oid[i].encoded != NULL && |
|
299 + strcmp(name, gss_enc2oid[i].encoded) != 0) |
|
300 + i++; |
|
301 + |
|
302 + if (gss_enc2oid[i].oid != NULL && ctx != NULL) |
|
303 + ssh_gssapi_set_oid(ctx, gss_enc2oid[i].oid); |
|
304 + |
|
305 + return gss_enc2oid[i].oid; |
|
306 +} |
|
307 + |
|
308 /* Check that the OID in a data stream matches that in the context */ |
|
309 int |
|
310 ssh_gssapi_check_oid(Gssctxt *ctx, void *data, size_t len) |
|
311 @@ -231,6 +386,9 @@ ssh_gssapi_import_name(Gssctxt *ctx, con |
|
312 OM_uint32 |
|
313 ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash) |
|
314 { |
|
315 + if (ctx == NULL) |
|
316 + return -1; |
|
317 + |
|
318 if ((ctx->major = gss_get_mic(&ctx->minor, ctx->context, |
|
319 GSS_C_QOP_DEFAULT, buffer, hash))) |
|
320 ssh_gssapi_error(ctx); |
|
321 @@ -238,6 +396,19 @@ ssh_gssapi_sign(Gssctxt *ctx, gss_buffer |
|
322 return (ctx->major); |
|
323 } |
|
324 |
|
325 +/* Priviledged when used by server */ |
|
326 +OM_uint32 |
|
327 +ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic) |
|
328 +{ |
|
329 + if (ctx == NULL) |
|
330 + return -1; |
|
331 + |
|
332 + ctx->major = gss_verify_mic(&ctx->minor, ctx->context, |
|
333 + gssbuf, gssmic, NULL); |
|
334 + |
|
335 + return (ctx->major); |
|
336 +} |
|
337 + |
|
338 void |
|
339 ssh_gssapi_buildmic(Buffer *b, const char *user, const char *service, |
|
340 const char *context) |
|
341 @@ -256,6 +427,10 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx |
|
342 gss_buffer_desc token = GSS_C_EMPTY_BUFFER; |
|
343 OM_uint32 major, minor; |
|
344 gss_OID_desc spnego_oid = {6, (void *)"\x2B\x06\x01\x05\x05\x02"}; |
|
345 + Gssctxt *intctx = NULL; |
|
346 + |
|
347 + if (ctx == NULL) |
|
348 + ctx = &intctx; |
|
349 |
|
350 /* RFC 4462 says we MUST NOT do SPNEGO */ |
|
351 if (oid->length == spnego_oid.length && |
|
352 @@ -274,7 +449,7 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx |
|
353 GSS_C_NO_BUFFER); |
|
354 } |
|
355 |
|
356 - if (GSS_ERROR(major)) |
|
357 + if (GSS_ERROR(major) || intctx != NULL) |
|
358 ssh_gssapi_delete_ctx(ctx); |
|
359 |
|
360 return (!GSS_ERROR(major)); |
|
361 diff -pur old/gss-serv.c new/gss-serv.c |
|
362 --- old/gss-serv.c |
|
363 +++ new/gss-serv.c |
|
364 @@ -1,7 +1,7 @@ |
|
365 /* $OpenBSD: gss-serv.c,v 1.29 2015/05/22 03:50:02 djm Exp $ */ |
|
366 |
|
367 /* |
|
368 - * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. |
|
369 + * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved. |
|
370 * |
|
371 * Redistribution and use in source and binary forms, with or without |
|
372 * modification, are permitted provided that the following conditions |
|
373 @@ -47,6 +47,7 @@ |
|
374 #include "servconf.h" |
|
375 |
|
376 #include "ssh-gss.h" |
|
377 +#include "monitor_wrap.h" |
|
378 |
|
379 extern ServerOptions options; |
|
380 |
|
381 @@ -142,6 +143,28 @@ ssh_gssapi_server_ctx(Gssctxt **ctx, gss |
|
382 } |
|
383 |
|
384 /* Unprivileged */ |
|
385 +char * |
|
386 +ssh_gssapi_server_mechanisms() { |
|
387 + gss_OID_set supported; |
|
388 + |
|
389 + ssh_gssapi_supported_oids(&supported); |
|
390 + return (ssh_gssapi_kex_mechs(supported, &ssh_gssapi_server_check_mech, |
|
391 + NULL)); |
|
392 +} |
|
393 + |
|
394 +/* Unprivileged */ |
|
395 +int |
|
396 +ssh_gssapi_server_check_mech(Gssctxt **dum, gss_OID oid, const char *data) { |
|
397 + Gssctxt *ctx = NULL; |
|
398 + int res; |
|
399 + |
|
400 + res = !GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctx, oid))); |
|
401 + ssh_gssapi_delete_ctx(&ctx); |
|
402 + |
|
403 + return (res); |
|
404 +} |
|
405 + |
|
406 +/* Unprivileged */ |
|
407 void |
|
408 ssh_gssapi_supported_oids(gss_OID_set *oidset) |
|
409 { |
|
410 @@ -151,7 +174,9 @@ ssh_gssapi_supported_oids(gss_OID_set *o |
|
411 gss_OID_set supported; |
|
412 |
|
413 gss_create_empty_oid_set(&min_status, oidset); |
|
414 - gss_indicate_mechs(&min_status, &supported); |
|
415 + |
|
416 + if (GSS_ERROR(gss_indicate_mechs(&min_status, &supported))) |
|
417 + return; |
|
418 |
|
419 while (supported_mechs[i]->name != NULL) { |
|
420 if (GSS_ERROR(gss_test_oid_set_member(&min_status, |
|
421 @@ -427,14 +452,4 @@ ssh_gssapi_userok(char *user) |
|
422 return (0); |
|
423 } |
|
424 |
|
425 -/* Privileged */ |
|
426 -OM_uint32 |
|
427 -ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic) |
|
428 -{ |
|
429 - ctx->major = gss_verify_mic(&ctx->minor, ctx->context, |
|
430 - gssbuf, gssmic, NULL); |
|
431 - |
|
432 - return (ctx->major); |
|
433 -} |
|
434 - |
|
435 #endif |
|
436 diff -pur old/kex.c new/kex.c |
|
437 --- old/kex.c |
|
438 +++ new/kex.c |
|
439 @@ -55,6 +55,10 @@ |
|
440 #include "sshbuf.h" |
|
441 #include "digest.h" |
|
442 |
|
443 +#ifdef GSSAPI |
|
444 +#include "ssh-gss.h" |
|
445 +#endif |
|
446 + |
|
447 #if OPENSSL_VERSION_NUMBER >= 0x00907000L |
|
448 # if defined(HAVE_EVP_SHA256) |
|
449 # define evp_ssh_sha256 EVP_sha256 |
|
450 @@ -95,6 +99,11 @@ static const struct kexalg kexalgs[] = { |
|
451 #if defined(HAVE_EVP_SHA256) || !defined(WITH_OPENSSL) |
|
452 { KEX_CURVE25519_SHA256, KEX_C25519_SHA256, 0, SSH_DIGEST_SHA256 }, |
|
453 #endif /* HAVE_EVP_SHA256 || !WITH_OPENSSL */ |
|
454 +#ifdef GSSAPI |
|
455 + { KEX_GSS_GEX_SHA1_ID, KEX_GSS_GEX_SHA1, 0, SSH_DIGEST_SHA1 }, |
|
456 + { KEX_GSS_GRP1_SHA1_ID, KEX_GSS_GRP1_SHA1, 0, SSH_DIGEST_SHA1 }, |
|
457 + { KEX_GSS_GRP14_SHA1_ID, KEX_GSS_GRP14_SHA1, 0, SSH_DIGEST_SHA1 }, |
|
458 +#endif |
|
459 { NULL, -1, -1, -1}, |
|
460 }; |
|
461 |
|
462 @@ -126,7 +135,7 @@ kex_alg_by_name(const char *name) |
|
463 const struct kexalg *k; |
|
464 |
|
465 for (k = kexalgs; k->name != NULL; k++) { |
|
466 - if (strcmp(k->name, name) == 0) |
|
467 + if (strncmp(k->name, name, strlen(k->name)) == 0) |
|
468 return k; |
|
469 } |
|
470 return NULL; |
|
471 diff -pur old/kex.h new/kex.h |
|
472 --- old/kex.h |
|
473 +++ new/kex.h |
|
474 @@ -93,6 +93,9 @@ enum kex_exchange { |
|
475 KEX_DH_GEX_SHA256, |
|
476 KEX_ECDH_SHA2, |
|
477 KEX_C25519_SHA256, |
|
478 + KEX_GSS_GRP1_SHA1, |
|
479 + KEX_GSS_GRP14_SHA1, |
|
480 + KEX_GSS_GEX_SHA1, |
|
481 KEX_MAX |
|
482 }; |
|
483 |
|
484 @@ -139,6 +142,10 @@ struct kex { |
|
485 u_int flags; |
|
486 int hash_alg; |
|
487 int ec_nid; |
|
488 +#ifdef GSSAPI |
|
489 + int gss_deleg_creds; |
|
490 + char *gss_host; |
|
491 +#endif |
|
492 char *client_version_string; |
|
493 char *server_version_string; |
|
494 char *failed_choice; |
|
495 @@ -186,6 +193,10 @@ int kexecdh_client(struct ssh *); |
|
496 int kexecdh_server(struct ssh *); |
|
497 int kexc25519_client(struct ssh *); |
|
498 int kexc25519_server(struct ssh *); |
|
499 +#ifdef GSSAPI |
|
500 +int kexgss_client(struct ssh *); |
|
501 +int kexgss_server(struct ssh *); |
|
502 +#endif |
|
503 |
|
504 int kex_dh_hash(const char *, const char *, |
|
505 const u_char *, size_t, const u_char *, size_t, const u_char *, size_t, |
|
506 diff -pur old/monitor.c new/monitor.c |
|
507 --- old/monitor.c |
|
508 +++ new/monitor.c |
|
509 @@ -160,6 +160,7 @@ int mm_answer_gss_setup_ctx(int, Buffer |
|
510 int mm_answer_gss_accept_ctx(int, Buffer *); |
|
511 int mm_answer_gss_userok(int, Buffer *); |
|
512 int mm_answer_gss_checkmic(int, Buffer *); |
|
513 +int mm_answer_gss_sign(int, Buffer *); |
|
514 #endif |
|
515 |
|
516 #ifdef SSH_AUDIT_EVENTS |
|
517 @@ -244,11 +245,17 @@ struct mon_table mon_dispatch_proto20[] |
|
518 {MONITOR_REQ_GSSSTEP, MON_ISAUTH, mm_answer_gss_accept_ctx}, |
|
519 {MONITOR_REQ_GSSUSEROK, MON_AUTH, mm_answer_gss_userok}, |
|
520 {MONITOR_REQ_GSSCHECKMIC, MON_ISAUTH, mm_answer_gss_checkmic}, |
|
521 + {MONITOR_REQ_GSSSIGN, MON_ONCE, mm_answer_gss_sign}, |
|
522 #endif |
|
523 {0, 0, NULL} |
|
524 }; |
|
525 |
|
526 struct mon_table mon_dispatch_postauth20[] = { |
|
527 +#ifdef GSSAPI |
|
528 + {MONITOR_REQ_GSSSETUP, 0, mm_answer_gss_setup_ctx}, |
|
529 + {MONITOR_REQ_GSSSTEP, 0, mm_answer_gss_accept_ctx}, |
|
530 + {MONITOR_REQ_GSSSIGN, 0, mm_answer_gss_sign}, |
|
531 +#endif |
|
532 #ifdef WITH_OPENSSL |
|
533 {MONITOR_REQ_MODULI, 0, mm_answer_moduli}, |
|
534 #endif |
|
535 @@ -363,6 +370,10 @@ monitor_child_preauth(Authctxt *_authctx |
|
536 /* Permit requests for moduli and signatures */ |
|
537 monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); |
|
538 monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); |
|
539 +#ifdef GSSAPI |
|
540 + /* and for the GSSAPI key exchange */ |
|
541 + monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1); |
|
542 +#endif |
|
543 } else { |
|
544 mon_dispatch = mon_dispatch_proto15; |
|
545 |
|
546 @@ -502,6 +513,10 @@ monitor_child_postauth(struct monitor *p |
|
547 monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); |
|
548 monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); |
|
549 monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); |
|
550 +#ifdef GSSAPI |
|
551 + /* and for the GSSAPI key exchange */ |
|
552 + monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1); |
|
553 +#endif |
|
554 } else { |
|
555 mon_dispatch = mon_dispatch_postauth15; |
|
556 monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); |
|
557 @@ -1927,6 +1942,13 @@ monitor_apply_keystate(struct monitor *p |
|
558 # endif |
|
559 #endif /* WITH_OPENSSL */ |
|
560 kex->kex[KEX_C25519_SHA256] = kexc25519_server; |
|
561 +#ifdef GSSAPI |
|
562 + if (options.gss_keyex) { |
|
563 + kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server; |
|
564 + kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_server; |
|
565 + kex->kex[KEX_GSS_GEX_SHA1] = kexgss_server; |
|
566 + } |
|
567 +#endif |
|
568 kex->load_host_public_key=&get_hostkey_public_by_type; |
|
569 kex->load_host_private_key=&get_hostkey_private_by_type; |
|
570 kex->host_key_index=&get_hostkey_index; |
|
571 @@ -2026,6 +2048,9 @@ mm_answer_gss_setup_ctx(int sock, Buffer |
|
572 OM_uint32 major; |
|
573 u_int len; |
|
574 |
|
575 + if (!options.gss_authentication && !options.gss_keyex) |
|
576 + fatal("In GSSAPI monitor when GSSAPI is disabled"); |
|
577 + |
|
578 goid.elements = buffer_get_string(m, &len); |
|
579 goid.length = len; |
|
580 |
|
581 @@ -2053,6 +2078,9 @@ mm_answer_gss_accept_ctx(int sock, Buffe |
|
582 OM_uint32 flags = 0; /* GSI needs this */ |
|
583 u_int len; |
|
584 |
|
585 + if (!options.gss_authentication && !options.gss_keyex) |
|
586 + fatal("In GSSAPI monitor when GSSAPI is disabled"); |
|
587 + |
|
588 in.value = buffer_get_string(m, &len); |
|
589 in.length = len; |
|
590 major = ssh_gssapi_accept_ctx(gsscontext, &in, &out, &flags); |
|
591 @@ -2070,6 +2098,7 @@ mm_answer_gss_accept_ctx(int sock, Buffe |
|
592 monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 0); |
|
593 monitor_permit(mon_dispatch, MONITOR_REQ_GSSUSEROK, 1); |
|
594 monitor_permit(mon_dispatch, MONITOR_REQ_GSSCHECKMIC, 1); |
|
595 + monitor_permit(mon_dispatch, MONITOR_REQ_GSSSIGN, 1); |
|
596 } |
|
597 return (0); |
|
598 } |
|
599 @@ -2081,6 +2110,9 @@ mm_answer_gss_checkmic(int sock, Buffer |
|
600 OM_uint32 ret; |
|
601 u_int len; |
|
602 |
|
603 + if (!options.gss_authentication && !options.gss_keyex) |
|
604 + fatal("In GSSAPI monitor when GSSAPI is disabled"); |
|
605 + |
|
606 gssbuf.value = buffer_get_string(m, &len); |
|
607 gssbuf.length = len; |
|
608 mic.value = buffer_get_string(m, &len); |
|
609 @@ -2107,6 +2139,9 @@ mm_answer_gss_userok(int sock, Buffer *m |
|
610 { |
|
611 int authenticated; |
|
612 |
|
613 + if (!options.gss_authentication && !options.gss_keyex) |
|
614 + fatal("In GSSAPI monitor when GSSAPI is disabled"); |
|
615 + |
|
616 authenticated = authctxt->valid && ssh_gssapi_userok(authctxt->user); |
|
617 |
|
618 buffer_clear(m); |
|
619 @@ -2120,5 +2155,47 @@ mm_answer_gss_userok(int sock, Buffer *m |
|
620 /* Monitor loop will terminate if authenticated */ |
|
621 return (authenticated); |
|
622 } |
|
623 + |
|
624 +int |
|
625 +mm_answer_gss_sign(int socket, Buffer *m) |
|
626 +{ |
|
627 + gss_buffer_desc data; |
|
628 + gss_buffer_desc hash = GSS_C_EMPTY_BUFFER; |
|
629 + OM_uint32 major, minor; |
|
630 + u_int len; |
|
631 + |
|
632 + if (!options.gss_authentication && !options.gss_keyex) |
|
633 + fatal("In GSSAPI monitor when GSSAPI is disabled"); |
|
634 + |
|
635 + data.value = buffer_get_string(m, &len); |
|
636 + data.length = len; |
|
637 + if (data.length != 20) |
|
638 + fatal("%s: data length incorrect: %d", __func__, |
|
639 + (int) data.length); |
|
640 + |
|
641 + /* Save the session ID on the first time around */ |
|
642 + if (session_id2_len == 0) { |
|
643 + session_id2_len = data.length; |
|
644 + session_id2 = xmalloc(session_id2_len); |
|
645 + memcpy(session_id2, data.value, session_id2_len); |
|
646 + } |
|
647 + major = ssh_gssapi_sign(gsscontext, &data, &hash); |
|
648 + |
|
649 + free(data.value); |
|
650 + |
|
651 + buffer_clear(m); |
|
652 + buffer_put_int(m, major); |
|
653 + buffer_put_string(m, hash.value, hash.length); |
|
654 + |
|
655 + mm_request_send(socket, MONITOR_ANS_GSSSIGN, m); |
|
656 + |
|
657 + gss_release_buffer(&minor, &hash); |
|
658 + |
|
659 + /* Turn on getpwnam permissions */ |
|
660 + monitor_permit(mon_dispatch, MONITOR_REQ_PWNAM, 1); |
|
661 + |
|
662 + return (0); |
|
663 +} |
|
664 + |
|
665 #endif /* GSSAPI */ |
|
666 |
|
667 diff -pur old/monitor.h new/monitor.h |
|
668 --- old/monitor.h |
|
669 +++ new/monitor.h |
|
670 @@ -68,6 +68,9 @@ enum monitor_reqtype { |
|
671 #ifdef PAM_ENHANCEMENT |
|
672 MONITOR_REQ_AUTHMETHOD = 114, |
|
673 #endif |
|
674 +#ifdef GSSAPI |
|
675 + MONITOR_REQ_GSSSIGN = 130, MONITOR_ANS_GSSSIGN = 131, |
|
676 +#endif |
|
677 }; |
|
678 |
|
679 struct mm_master; |
|
680 diff -pur old/monitor_wrap.c new/monitor_wrap.c |
|
681 --- old/monitor_wrap.c |
|
682 +++ new/monitor_wrap.c |
|
683 @@ -1103,5 +1103,28 @@ mm_ssh_gssapi_userok(char *user) |
|
684 debug3("%s: user %sauthenticated",__func__, authenticated ? "" : "not "); |
|
685 return (authenticated); |
|
686 } |
|
687 + |
|
688 +OM_uint32 |
|
689 +mm_ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_desc *data, gss_buffer_desc *hash) |
|
690 +{ |
|
691 + Buffer m; |
|
692 + OM_uint32 major; |
|
693 + u_int len; |
|
694 + |
|
695 + buffer_init(&m); |
|
696 + buffer_put_string(&m, data->value, data->length); |
|
697 + |
|
698 + mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSSIGN, &m); |
|
699 + mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSSIGN, &m); |
|
700 + |
|
701 + major = buffer_get_int(&m); |
|
702 + hash->value = buffer_get_string(&m, &len); |
|
703 + hash->length = len; |
|
704 + |
|
705 + buffer_free(&m); |
|
706 + |
|
707 + return(major); |
|
708 +} |
|
709 + |
|
710 #endif /* GSSAPI */ |
|
711 |
|
712 diff -pur old/monitor_wrap.h new/monitor_wrap.h |
|
713 --- old/monitor_wrap.h |
|
714 +++ new/monitor_wrap.h |
|
715 @@ -60,6 +60,7 @@ OM_uint32 mm_ssh_gssapi_accept_ctx(Gssct |
|
716 gss_buffer_desc *, gss_buffer_desc *, OM_uint32 *); |
|
717 int mm_ssh_gssapi_userok(char *user); |
|
718 OM_uint32 mm_ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t); |
|
719 +OM_uint32 mm_ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t); |
|
720 #endif |
|
721 |
|
722 #ifdef USE_PAM |
|
723 diff -pur old/readconf.c new/readconf.c |
|
724 --- old/readconf.c |
|
725 +++ new/readconf.c |
|
726 @@ -147,6 +147,7 @@ typedef enum { |
|
727 oClearAllForwardings, oNoHostAuthenticationForLocalhost, |
|
728 oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout, |
|
729 oAddressFamily, oGssAuthentication, oGssDelegateCreds, |
|
730 + oGssKeyEx, |
|
731 oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly, |
|
732 oSendEnv, oControlPath, oControlMaster, oControlPersist, |
|
733 oHashKnownHosts, |
|
734 @@ -198,11 +199,15 @@ static struct { |
|
735 { "gssauthentication", oGssAuthentication }, /* alias */ |
|
736 { "gssapidelegatecredentials", oGssDelegateCreds }, |
|
737 { "gssdelegatecreds", oGssDelegateCreds }, /* alias */ |
|
738 + { "gssapikeyexchange", oGssKeyEx }, |
|
739 + { "gsskeyex", oGssKeyEx }, /* alias */ |
|
740 #else |
|
741 { "gssapiauthentication", oUnsupported }, |
|
742 { "gssauthentication", oUnsupported }, |
|
743 { "gssapidelegatecredentials", oUnsupported }, |
|
744 { "gssdelegatecreds", oUnsupported }, |
|
745 + { "gssapikeyexchange", oUnsupported }, |
|
746 + { "gsskeyex", oUnsupported }, |
|
747 #endif |
|
748 { "fallbacktorsh", oDeprecated }, |
|
749 { "usersh", oDeprecated }, |
|
750 @@ -933,6 +938,10 @@ parse_time: |
|
751 intptr = &options->gss_authentication; |
|
752 goto parse_flag; |
|
753 |
|
754 + case oGssKeyEx: |
|
755 + intptr = &options->gss_keyex; |
|
756 + goto parse_flag; |
|
757 + |
|
758 case oGssDelegateCreds: |
|
759 intptr = &options->gss_deleg_creds; |
|
760 goto parse_flag; |
|
761 @@ -1647,6 +1656,7 @@ initialize_options(Options * options) |
|
762 options->pubkey_authentication = -1; |
|
763 options->challenge_response_authentication = -1; |
|
764 options->gss_authentication = -1; |
|
765 + options->gss_keyex = -1; |
|
766 options->gss_deleg_creds = -1; |
|
767 options->password_authentication = -1; |
|
768 options->kbd_interactive_authentication = -1; |
|
769 @@ -1786,6 +1796,12 @@ fill_default_options(Options * options) |
|
770 #else |
|
771 options->gss_authentication = 0; |
|
772 #endif |
|
773 + if (options->gss_keyex == -1) |
|
774 +#ifdef OPTION_DEFAULT_VALUE |
|
775 + options->gss_keyex = 1; |
|
776 +#else |
|
777 + options->gss_keyex = 0; |
|
778 +#endif |
|
779 if (options->gss_deleg_creds == -1) |
|
780 options->gss_deleg_creds = 0; |
|
781 if (options->password_authentication == -1) |
|
782 diff -pur old/readconf.h new/readconf.h |
|
783 --- old/readconf.h |
|
784 +++ new/readconf.h |
|
785 @@ -45,6 +45,7 @@ typedef struct { |
|
786 int challenge_response_authentication; |
|
787 /* Try S/Key or TIS, authentication. */ |
|
788 int gss_authentication; /* Try GSS authentication */ |
|
789 + int gss_keyex; /* Try GSS key exchange */ |
|
790 int gss_deleg_creds; /* Delegate GSS credentials */ |
|
791 int password_authentication; /* Try password |
|
792 * authentication. */ |
|
793 diff -pur old/servconf.c new/servconf.c |
|
794 --- old/servconf.c |
|
795 +++ new/servconf.c |
|
796 @@ -117,6 +117,7 @@ initialize_server_options(ServerOptions |
|
797 options->kerberos_ticket_cleanup = -1; |
|
798 options->kerberos_get_afs_token = -1; |
|
799 options->gss_authentication=-1; |
|
800 + options->gss_keyex = -1; |
|
801 options->gss_cleanup_creds = -1; |
|
802 options->gss_strict_acceptor = -1; |
|
803 options->password_authentication = -1; |
|
804 @@ -300,6 +301,12 @@ fill_default_server_options(ServerOption |
|
805 #else |
|
806 options->gss_authentication = 0; |
|
807 #endif |
|
808 + if (options->gss_keyex == -1) |
|
809 +#ifdef OPTION_DEFAULT_VALUE |
|
810 + options->gss_keyex = 1; |
|
811 +#else |
|
812 + options->gss_keyex = 0; |
|
813 +#endif |
|
814 if (options->gss_cleanup_creds == -1) |
|
815 options->gss_cleanup_creds = 1; |
|
816 if (options->gss_strict_acceptor == -1) |
|
817 @@ -442,6 +449,7 @@ typedef enum { |
|
818 sHostbasedUsesNameFromPacketOnly, sHostbasedAcceptedKeyTypes, |
|
819 sHostKeyAlgorithms, |
|
820 sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile, |
|
821 + sGssKeyEx, |
|
822 sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor, |
|
823 sAcceptEnv, sPermitTunnel, |
|
824 sMatch, sPermitOpen, sForceCommand, sChrootDirectory, |
|
825 @@ -519,6 +527,8 @@ static struct { |
|
826 #ifdef GSSAPI |
|
827 { "gssapiauthentication", sGssAuthentication, SSHCFG_ALL }, |
|
828 { "gssauthentication", sGssAuthentication, SSHCFG_ALL }, /* alias */ |
|
829 + { "gssapikeyexchange", sGssKeyEx, SSHCFG_ALL }, |
|
830 + { "gsskeyex", sGssKeyEx, SSHCFG_ALL }, /* alias */ |
|
831 #ifdef USE_GSS_STORE_CRED |
|
832 { "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL }, |
|
833 #else /* USE_GSS_STORE_CRED */ |
|
834 @@ -528,6 +538,8 @@ static struct { |
|
835 #else |
|
836 { "gssapiauthentication", sUnsupported, SSHCFG_ALL }, |
|
837 { "gssauthentication", sUnsupported, SSHCFG_ALL }, /* alias */ |
|
838 + { "gssapikeyexchange", sUnsupported,, SSHCFG_ALL }, |
|
839 + { "gsskeyex", sUnsupported,, SSHCFG_ALL }, |
|
840 { "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL }, |
|
841 { "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL }, |
|
842 #endif |
|
843 @@ -1311,6 +1323,10 @@ process_server_config_line(ServerOptions |
|
844 intptr = &options->gss_authentication; |
|
845 goto parse_flag; |
|
846 |
|
847 + case sGssKeyEx: |
|
848 + intptr = &options->gss_keyex; |
|
849 + goto parse_flag; |
|
850 + |
|
851 case sGssCleanupCreds: |
|
852 intptr = &options->gss_cleanup_creds; |
|
853 goto parse_flag; |
|
854 @@ -2357,6 +2373,7 @@ dump_config(ServerOptions *o) |
|
855 #endif |
|
856 #ifdef GSSAPI |
|
857 dump_cfg_fmtint(sGssAuthentication, o->gss_authentication); |
|
858 + dump_cfg_fmtint(sGssKeyEx, o->gss_keyex); |
|
859 #ifndef USE_GSS_STORE_CRED |
|
860 dump_cfg_fmtint(sGssCleanupCreds, o->gss_cleanup_creds); |
|
861 #endif /* !USE_GSS_STORE_CRED */ |
|
862 diff -pur old/servconf.h new/servconf.h |
|
863 --- old/servconf.h |
|
864 +++ new/servconf.h |
|
865 @@ -122,6 +122,7 @@ typedef struct { |
|
866 int kerberos_get_afs_token; /* If true, try to get AFS token if |
|
867 * authenticated with Kerberos. */ |
|
868 int gss_authentication; /* If true, permit GSSAPI authentication */ |
|
869 + int gss_keyex; /* If true, permit GSSAPI key exchange */ |
|
870 int gss_cleanup_creds; /* If true, destroy cred cache on logout */ |
|
871 int gss_strict_acceptor; /* If true, restrict the GSSAPI acceptor name */ |
|
872 int password_authentication; /* If true, permit password |
|
873 diff -pur old/ssh-gss.h new/ssh-gss.h |
|
874 --- old/ssh-gss.h |
|
875 +++ new/ssh-gss.h |
|
876 @@ -61,6 +61,17 @@ |
|
877 |
|
878 #define SSH_GSS_OIDTYPE 0x06 |
|
879 |
|
880 +#define SSH2_MSG_KEXGSS_INIT 30 |
|
881 +#define SSH2_MSG_KEXGSS_CONTINUE 31 |
|
882 +#define SSH2_MSG_KEXGSS_COMPLETE 32 |
|
883 +#define SSH2_MSG_KEXGSS_HOSTKEY 33 |
|
884 +#define SSH2_MSG_KEXGSS_ERROR 34 |
|
885 +#define SSH2_MSG_KEXGSS_GROUPREQ 40 |
|
886 +#define SSH2_MSG_KEXGSS_GROUP 41 |
|
887 +#define KEX_GSS_GRP1_SHA1_ID "gss-group1-sha1-" |
|
888 +#define KEX_GSS_GRP14_SHA1_ID "gss-group14-sha1-" |
|
889 +#define KEX_GSS_GEX_SHA1_ID "gss-gex-sha1-" |
|
890 + |
|
891 typedef struct { |
|
892 char *filename; |
|
893 char *envvar; |
|
894 @@ -98,6 +109,7 @@ typedef struct { |
|
895 } Gssctxt; |
|
896 |
|
897 extern ssh_gssapi_mech *supported_mechs[]; |
|
898 +extern Gssctxt *gss_kex_context; |
|
899 |
|
900 int ssh_gssapi_check_oid(Gssctxt *, void *, size_t); |
|
901 void ssh_gssapi_set_oid_data(Gssctxt *, void *, size_t); |
|
902 @@ -122,6 +134,11 @@ void ssh_gssapi_buildmic(Buffer *, const |
|
903 int ssh_gssapi_check_mechanism(Gssctxt **, gss_OID, const char *); |
|
904 |
|
905 /* In the server */ |
|
906 +typedef int ssh_gssapi_check_fn(Gssctxt **, gss_OID, const char *); |
|
907 +char *ssh_gssapi_client_mechanisms(const char *host); |
|
908 +char *ssh_gssapi_kex_mechs(gss_OID_set, ssh_gssapi_check_fn *, const char *); |
|
909 +gss_OID ssh_gssapi_id_kex(Gssctxt *, char *, int); |
|
910 +int ssh_gssapi_server_check_mech(Gssctxt **,gss_OID, const char *); |
|
911 OM_uint32 ssh_gssapi_server_ctx(Gssctxt **, gss_OID); |
|
912 int ssh_gssapi_userok(char *name); |
|
913 OM_uint32 ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t); |
|
914 @@ -129,6 +146,8 @@ void ssh_gssapi_do_child(char ***, u_int |
|
915 void ssh_gssapi_cleanup_creds(void); |
|
916 void ssh_gssapi_storecreds(void); |
|
917 |
|
918 +char *ssh_gssapi_server_mechanisms(void); |
|
919 +int ssh_gssapi_oid_table_ok(); |
|
920 #endif /* GSSAPI */ |
|
921 |
|
922 #endif /* _SSH_GSS_H */ |
|
923 diff -pur old/ssh_config new/ssh_config |
|
924 --- old/ssh_config |
|
925 +++ new/ssh_config |
|
926 @@ -26,6 +26,7 @@ |
|
927 # HostbasedAuthentication no |
|
928 # GSSAPIAuthentication no |
|
929 # GSSAPIDelegateCredentials no |
|
930 +# GSSAPIKeyExchange yes |
|
931 # BatchMode no |
|
932 # CheckHostIP yes |
|
933 # AddressFamily any |
|
934 diff -pur old/ssh_config.5 new/ssh_config.5 |
|
935 --- old/ssh_config.5 |
|
936 +++ new/ssh_config.5 |
|
937 @@ -757,6 +757,12 @@ Specifies whether user authentication ba |
|
938 The default on Solaris is |
|
939 .Dq yes . |
|
940 Note that this option applies to protocol version 2 only. |
|
941 +.It Cm GSSAPIKeyExchange |
|
942 +Specifies whether key exchange based on GSSAPI may be used. When using |
|
943 +GSSAPI key exchange the server need not have a host key. |
|
944 +The default on Solaris is |
|
945 +.Dq yes . |
|
946 +Note that this option applies to protocol version 2 only. |
|
947 .It Cm GSSAPIDelegateCredentials |
|
948 Forward (delegate) credentials to the server. |
|
949 The default is |
|
950 diff -pur old/sshconnect2.c new/sshconnect2.c |
|
951 --- old/sshconnect2.c |
|
952 +++ new/sshconnect2.c |
|
953 @@ -163,12 +163,37 @@ ssh_kex2(char *host, struct sockaddr *ho |
|
954 char *myproposal[PROPOSAL_MAX] = { KEX_CLIENT }; |
|
955 struct kex *kex; |
|
956 int r; |
|
957 +#ifdef GSSAPI |
|
958 + char *orig = NULL, *gss = NULL; |
|
959 + char *gss_host = NULL; |
|
960 +#endif |
|
961 + |
|
962 |
|
963 xxx_host = host; |
|
964 xxx_hostaddr = hostaddr; |
|
965 |
|
966 + if (options.kex_algorithms != NULL) |
|
967 + myproposal[PROPOSAL_KEX_ALGS] = options.kex_algorithms; |
|
968 + |
|
969 +#ifdef GSSAPI |
|
970 + if (options.gss_keyex) { |
|
971 + /* Add the GSSAPI mechanisms currently supported on this |
|
972 + * client to the key exchange algorithm proposal */ |
|
973 + orig = myproposal[PROPOSAL_KEX_ALGS]; |
|
974 + |
|
975 + gss_host = (char *)get_canonical_hostname(1); |
|
976 + |
|
977 + gss = ssh_gssapi_client_mechanisms(gss_host); |
|
978 + if (gss) { |
|
979 + debug("Offering GSSAPI proposal: %s", gss); |
|
980 + xasprintf(&myproposal[PROPOSAL_KEX_ALGS], |
|
981 + "%s,%s", gss, orig); |
|
982 + } |
|
983 + } |
|
984 +#endif |
|
985 + |
|
986 myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal( |
|
987 - options.kex_algorithms); |
|
988 + myproposal[PROPOSAL_KEX_ALGS]); |
|
989 myproposal[PROPOSAL_ENC_ALGS_CTOS] = |
|
990 compat_cipher_proposal(options.ciphers); |
|
991 myproposal[PROPOSAL_ENC_ALGS_STOC] = |
|
992 @@ -197,6 +222,17 @@ ssh_kex2(char *host, struct sockaddr *ho |
|
993 order_hostkeyalgs(host, hostaddr, port)); |
|
994 } |
|
995 |
|
996 +#ifdef GSSAPI |
|
997 + /* If we've got GSSAPI algorithms, then we also support the |
|
998 + * 'null' hostkey, as a last resort */ |
|
999 + if (options.gss_keyex && gss) { |
|
1000 + orig = myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]; |
|
1001 + xasprintf(&myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS], |
|
1002 + "%s,null", orig); |
|
1003 + free(gss); |
|
1004 + } |
|
1005 +#endif |
|
1006 + |
|
1007 if (options.rekey_limit || options.rekey_interval) |
|
1008 packet_set_rekey_limits((u_int32_t)options.rekey_limit, |
|
1009 (time_t)options.rekey_interval); |
|
1010 @@ -215,9 +251,22 @@ ssh_kex2(char *host, struct sockaddr *ho |
|
1011 # endif |
|
1012 #endif |
|
1013 kex->kex[KEX_C25519_SHA256] = kexc25519_client; |
|
1014 +#ifdef GSSAPI |
|
1015 + if (options.gss_keyex) { |
|
1016 + kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_client; |
|
1017 + kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_client; |
|
1018 + kex->kex[KEX_GSS_GEX_SHA1] = kexgss_client; |
|
1019 + } |
|
1020 +#endif |
|
1021 kex->client_version_string=client_version_string; |
|
1022 kex->server_version_string=server_version_string; |
|
1023 kex->verify_host_key=&verify_host_key_callback; |
|
1024 +#ifdef GSSAPI |
|
1025 + if (options.gss_keyex) { |
|
1026 + kex->gss_deleg_creds = options.gss_deleg_creds; |
|
1027 + kex->gss_host = gss_host; |
|
1028 + } |
|
1029 +#endif |
|
1030 |
|
1031 dispatch_run(DISPATCH_BLOCK, &kex->done, active_state); |
|
1032 |
|
1033 @@ -310,6 +359,7 @@ int input_gssapi_token(int type, u_int32 |
|
1034 int input_gssapi_hash(int type, u_int32_t, void *); |
|
1035 int input_gssapi_error(int, u_int32_t, void *); |
|
1036 int input_gssapi_errtok(int, u_int32_t, void *); |
|
1037 +int userauth_gsskeyex(Authctxt *authctxt); |
|
1038 #endif |
|
1039 |
|
1040 void userauth(Authctxt *, char *); |
|
1041 @@ -325,6 +375,11 @@ static char *authmethods_get(void); |
|
1042 |
|
1043 Authmethod authmethods[] = { |
|
1044 #ifdef GSSAPI |
|
1045 + {"gssapi-keyex", |
|
1046 + userauth_gsskeyex, |
|
1047 + NULL, |
|
1048 + &options.gss_authentication, |
|
1049 + NULL}, |
|
1050 {"gssapi-with-mic", |
|
1051 userauth_gssapi, |
|
1052 NULL, |
|
1053 @@ -649,7 +704,10 @@ userauth_gssapi(Authctxt *authctxt) |
|
1054 * once. */ |
|
1055 |
|
1056 if (gss_supported == NULL) |
|
1057 - gss_indicate_mechs(&min, &gss_supported); |
|
1058 + if (GSS_ERROR(gss_indicate_mechs(&min, &gss_supported))) { |
|
1059 + gss_supported = NULL; |
|
1060 + return 0; |
|
1061 + } |
|
1062 |
|
1063 /* Check to see if the mechanism is usable before we offer it */ |
|
1064 while (mech < gss_supported->count && !ok) { |
|
1065 @@ -753,8 +811,8 @@ input_gssapi_response(int type, u_int32_ |
|
1066 { |
|
1067 Authctxt *authctxt = ctxt; |
|
1068 Gssctxt *gssctxt; |
|
1069 - int oidlen; |
|
1070 - char *oidv; |
|
1071 + u_int oidlen; |
|
1072 + u_char *oidv; |
|
1073 |
|
1074 if (authctxt == NULL) |
|
1075 fatal("input_gssapi_response: no authentication context"); |
|
1076 @@ -867,6 +925,48 @@ input_gssapi_error(int type, u_int32_t p |
|
1077 free(lang); |
|
1078 return 0; |
|
1079 } |
|
1080 + |
|
1081 +int |
|
1082 +userauth_gsskeyex(Authctxt *authctxt) |
|
1083 +{ |
|
1084 + Buffer b; |
|
1085 + gss_buffer_desc gssbuf; |
|
1086 + gss_buffer_desc mic = GSS_C_EMPTY_BUFFER; |
|
1087 + OM_uint32 ms; |
|
1088 + |
|
1089 + static int attempt = 0; |
|
1090 + if (attempt++ >= 1) |
|
1091 + return (0); |
|
1092 + |
|
1093 + if (gss_kex_context == NULL) { |
|
1094 + debug("No valid Key exchange context"); |
|
1095 + return (0); |
|
1096 + } |
|
1097 + |
|
1098 + ssh_gssapi_buildmic(&b, authctxt->server_user, authctxt->service, |
|
1099 + "gssapi-keyex"); |
|
1100 + |
|
1101 + gssbuf.value = buffer_ptr(&b); |
|
1102 + gssbuf.length = buffer_len(&b); |
|
1103 + |
|
1104 + if (GSS_ERROR(ssh_gssapi_sign(gss_kex_context, &gssbuf, &mic))) { |
|
1105 + buffer_free(&b); |
|
1106 + return (0); |
|
1107 + } |
|
1108 + |
|
1109 + packet_start(SSH2_MSG_USERAUTH_REQUEST); |
|
1110 + packet_put_cstring(authctxt->server_user); |
|
1111 + packet_put_cstring(authctxt->service); |
|
1112 + packet_put_cstring(authctxt->method->name); |
|
1113 + packet_put_string(mic.value, mic.length); |
|
1114 + packet_send(); |
|
1115 + |
|
1116 + buffer_free(&b); |
|
1117 + gss_release_buffer(&ms, &mic); |
|
1118 + |
|
1119 + return (1); |
|
1120 +} |
|
1121 + |
|
1122 #endif /* GSSAPI */ |
|
1123 |
|
1124 int |
|
1125 diff -pur old/sshd.c new/sshd.c |
|
1126 --- old/sshd.c |
|
1127 +++ new/sshd.c |
|
1128 @@ -1827,10 +1827,13 @@ main(int ac, char **av) |
|
1129 logit("Disabling protocol version 1. Could not load host key"); |
|
1130 options.protocol &= ~SSH_PROTO_1; |
|
1131 } |
|
1132 +#ifndef GSSAPI |
|
1133 + /* The GSSAPI key exchange can run without a host key */ |
|
1134 if ((options.protocol & SSH_PROTO_2) && !sensitive_data.have_ssh2_key) { |
|
1135 logit("Disabling protocol version 2. Could not load host key"); |
|
1136 options.protocol &= ~SSH_PROTO_2; |
|
1137 } |
|
1138 +#endif |
|
1139 if (!(options.protocol & (SSH_PROTO_1|SSH_PROTO_2))) { |
|
1140 logit("sshd: no hostkeys available -- exiting."); |
|
1141 exit(1); |
|
1142 @@ -2588,6 +2591,48 @@ do_ssh2_kex(void) |
|
1143 myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = compat_pkalg_proposal( |
|
1144 list_hostkey_types()); |
|
1145 |
|
1146 +#ifdef GSSAPI |
|
1147 + { |
|
1148 + char *orig; |
|
1149 + char *gss = NULL; |
|
1150 + char *newstr = NULL; |
|
1151 + orig = myproposal[PROPOSAL_KEX_ALGS]; |
|
1152 + |
|
1153 + /* |
|
1154 + * If we don't have a host key, then there's no point advertising |
|
1155 + * the other key exchange algorithms |
|
1156 + */ |
|
1157 + |
|
1158 + if (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]) == 0) |
|
1159 + orig = NULL; |
|
1160 + |
|
1161 + if (options.gss_keyex) |
|
1162 + gss = ssh_gssapi_server_mechanisms(); |
|
1163 + else |
|
1164 + gss = NULL; |
|
1165 + |
|
1166 + if (gss && orig) |
|
1167 + xasprintf(&newstr, "%s,%s", gss, orig); |
|
1168 + else if (gss) |
|
1169 + newstr = gss; |
|
1170 + else if (orig) |
|
1171 + newstr = orig; |
|
1172 + |
|
1173 + /* |
|
1174 + * If we've got GSSAPI mechanisms, then we've got the 'null' host |
|
1175 + * key alg, but we can't tell people about it unless its the only |
|
1176 + * host key algorithm we support |
|
1177 + */ |
|
1178 + if (gss && (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS])) == 0) |
|
1179 + myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = "null"; |
|
1180 + |
|
1181 + if (newstr) |
|
1182 + myproposal[PROPOSAL_KEX_ALGS] = newstr; |
|
1183 + else |
|
1184 + fatal("No supported key exchange algorithms"); |
|
1185 + } |
|
1186 +#endif |
|
1187 + |
|
1188 /* start key exchange */ |
|
1189 if ((r = kex_setup(active_state, myproposal)) != 0) |
|
1190 fatal("kex_setup: %s", ssh_err(r)); |
|
1191 @@ -2602,6 +2647,13 @@ do_ssh2_kex(void) |
|
1192 # endif |
|
1193 #endif |
|
1194 kex->kex[KEX_C25519_SHA256] = kexc25519_server; |
|
1195 +#ifdef GSSAPI |
|
1196 + if (options.gss_keyex) { |
|
1197 + kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server; |
|
1198 + kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_server; |
|
1199 + kex->kex[KEX_GSS_GEX_SHA1] = kexgss_server; |
|
1200 + } |
|
1201 +#endif |
|
1202 kex->server = 1; |
|
1203 kex->client_version_string=client_version_string; |
|
1204 kex->server_version_string=server_version_string; |
|
1205 diff -pur old/sshd_config new/sshd_config |
|
1206 --- old/sshd_config |
|
1207 +++ new/sshd_config |
|
1208 @@ -82,8 +82,9 @@ AuthorizedKeysFile .ssh/authorized_keys |
|
1209 #KerberosGetAFSToken no |
|
1210 |
|
1211 # GSSAPI options |
|
1212 -#GSSAPIAuthentication no |
|
1213 +#GSSAPIAuthentication yes |
|
1214 #GSSAPICleanupCredentials yes |
|
1215 +#GSSAPIKeyExchange yes |
|
1216 |
|
1217 # Set this to 'yes' to enable PAM authentication, account processing, |
|
1218 # and session processing. If this is enabled, PAM authentication will |
|
1219 diff -pur old/sshd_config.5 new/sshd_config.5 |
|
1220 --- old/sshd_config.5 |
|
1221 +++ new/sshd_config.5 |
|
1222 @@ -621,6 +621,12 @@ Specifies whether user authentication ba |
|
1223 The default on Solaris is |
|
1224 .Dq yes . |
|
1225 Note that this option applies to protocol version 2 only. |
|
1226 +.It Cm GSSAPIKeyExchange |
|
1227 +Specifies whether key exchange based on GSSAPI is allowed. GSSAPI key exchange |
|
1228 +doesn't rely on ssh keys to verify host identity. |
|
1229 +The default on Solaris is |
|
1230 +.Dq yes . |
|
1231 +Note that this option applies to protocol version 2 only. |
|
1232 .It Cm GSSAPICleanupCredentials |
|
1233 Specifies whether to automatically destroy the user's credentials cache |
|
1234 on logout. |
|
1235 diff -pur old/sshkey.c new/sshkey.c |
|
1236 --- old/sshkey.c |
|
1237 +++ new/sshkey.c |
|
1238 @@ -112,6 +112,7 @@ static const struct keytype keytypes[] = |
|
1239 # endif /* OPENSSL_HAS_NISTP521 */ |
|
1240 # endif /* OPENSSL_HAS_ECC */ |
|
1241 #endif /* WITH_OPENSSL */ |
|
1242 + { "null", "null", KEY_NULL, 0, 0 }, |
|
1243 { NULL, NULL, -1, -1, 0 } |
|
1244 }; |
|
1245 |
|
1246 diff -pur old/sshkey.h new/sshkey.h |
|
1247 --- old/sshkey.h |
|
1248 +++ new/sshkey.h |
|
1249 @@ -62,6 +62,7 @@ enum sshkey_types { |
|
1250 KEY_DSA_CERT, |
|
1251 KEY_ECDSA_CERT, |
|
1252 KEY_ED25519_CERT, |
|
1253 + KEY_NULL, |
|
1254 KEY_UNSPEC |
|
1255 }; |
|
1256 |