summaryrefslogtreecommitdiff
path: root/debian/patches/gssapi.patch
diff options
context:
space:
mode:
authorColin Watson <cjwatson@debian.org>2019-06-05 06:41:44 +0100
committerColin Watson <cjwatson@debian.org>2019-06-09 22:09:07 +0100
commit865a97e05b6aab1619e1c8eeb33ccb8f9a9e48d3 (patch)
tree7bb2128eb663180bacfabca88f26d26bf0733824 /debian/patches/gssapi.patch
parentba627ba172d6649919baedff5ba2789610da382a (diff)
parent7d50f9e5be88179325983a1f58c9d51bb58f025a (diff)
New upstream release (8.0p1)
Diffstat (limited to 'debian/patches/gssapi.patch')
-rw-r--r--debian/patches/gssapi.patch2539
1 files changed, 1637 insertions, 902 deletions
diff --git a/debian/patches/gssapi.patch b/debian/patches/gssapi.patch
index f62bf6672..45d131d27 100644
--- a/debian/patches/gssapi.patch
+++ b/debian/patches/gssapi.patch
@@ -1,4 +1,4 @@
1From 72b1d308e6400194ef6e4e7dd45bfa48fa39b5e6 Mon Sep 17 00:00:00 2001 1From 7ce79be85036c4b36937f1b1ba85f6094068412c Mon Sep 17 00:00:00 2001
2From: Simon Wilkinson <simon@sxw.org.uk> 2From: Simon Wilkinson <simon@sxw.org.uk>
3Date: Sun, 9 Feb 2014 16:09:48 +0000 3Date: Sun, 9 Feb 2014 16:09:48 +0000
4Subject: GSSAPI key exchange support 4Subject: GSSAPI key exchange support
@@ -16,185 +16,69 @@ have it merged into the main openssh package rather than having separate
16-krb5 packages (as we used to have). It seems to have a generally good 16-krb5 packages (as we used to have). It seems to have a generally good
17security history. 17security history.
18 18
19Origin: other, https://github.com/openssh-gsskex/openssh-gsskex/commits/debian/master
19Bug: https://bugzilla.mindrot.org/show_bug.cgi?id=1242 20Bug: https://bugzilla.mindrot.org/show_bug.cgi?id=1242
20Last-Updated: 2018-10-20 21Last-Updated: 2019-06-05
21 22
22Patch-Name: gssapi.patch 23Patch-Name: gssapi.patch
23--- 24---
24 ChangeLog.gssapi | 113 ++++++++++++++++ 25 Makefile.in | 3 +-
25 Makefile.in | 3 +- 26 auth-krb5.c | 17 +-
26 auth-krb5.c | 17 ++- 27 auth.c | 96 +-------
27 auth.c | 96 +------------ 28 auth2-gss.c | 56 ++++-
28 auth2-gss.c | 54 +++++++- 29 auth2.c | 2 +
29 auth2.c | 2 + 30 canohost.c | 93 ++++++++
30 canohost.c | 93 +++++++++++++ 31 canohost.h | 3 +
31 canohost.h | 3 + 32 clientloop.c | 15 +-
32 clientloop.c | 15 ++- 33 configure.ac | 24 ++
33 config.h.in | 6 + 34 gss-genr.c | 300 +++++++++++++++++++++++-
34 configure.ac | 24 ++++ 35 gss-serv-krb5.c | 85 ++++++-
35 gss-genr.c | 280 +++++++++++++++++++++++++++++++++++++- 36 gss-serv.c | 186 +++++++++++++--
36 gss-serv-krb5.c | 85 +++++++++++- 37 hmac.c | 1 +
37 gss-serv.c | 184 +++++++++++++++++++++++-- 38 kex.c | 66 +++++-
38 kex.c | 19 +++ 39 kex.h | 29 +++
39 kex.h | 14 ++ 40 kexdh.c | 10 +
40 kexgssc.c | 341 +++++++++++++++++++++++++++++++++++++++++++++++ 41 kexgen.c | 2 +-
41 kexgsss.c | 300 +++++++++++++++++++++++++++++++++++++++++ 42 kexgssc.c | 606 ++++++++++++++++++++++++++++++++++++++++++++++++
42 monitor.c | 122 +++++++++++++++-- 43 kexgsss.c | 474 +++++++++++++++++++++++++++++++++++++
43 monitor.h | 3 + 44 mac.c | 1 +
44 monitor_wrap.c | 53 +++++++- 45 monitor.c | 139 ++++++++++-
45 monitor_wrap.h | 4 +- 46 monitor.h | 2 +
46 opacket.c | 2 +- 47 monitor_wrap.c | 57 ++++-
47 opacket.h | 2 +- 48 monitor_wrap.h | 4 +-
48 readconf.c | 43 ++++++ 49 readconf.c | 70 ++++++
49 readconf.h | 5 + 50 readconf.h | 6 +
50 servconf.c | 26 ++++ 51 servconf.c | 47 ++++
51 servconf.h | 2 + 52 servconf.h | 3 +
52 ssh-gss.h | 41 +++++- 53 session.c | 10 +-
53 ssh_config | 2 + 54 ssh-gss.h | 50 +++-
54 ssh_config.5 | 32 +++++ 55 ssh.1 | 8 +
55 sshconnect2.c | 133 +++++++++++++++++- 56 ssh.c | 4 +-
56 sshd.c | 110 +++++++++++++++ 57 ssh_config | 2 +
57 sshd_config | 2 + 58 ssh_config.5 | 57 +++++
58 sshd_config.5 | 10 ++ 59 sshconnect2.c | 140 ++++++++++-
59 sshkey.c | 3 +- 60 sshd.c | 120 +++++++++-
60 sshkey.h | 1 + 61 sshd_config | 2 +
61 37 files changed, 2099 insertions(+), 146 deletions(-) 62 sshd_config.5 | 30 +++
62 create mode 100644 ChangeLog.gssapi 63 sshkey.c | 3 +-
64 sshkey.h | 1 +
65 40 files changed, 2664 insertions(+), 160 deletions(-)
63 create mode 100644 kexgssc.c 66 create mode 100644 kexgssc.c
64 create mode 100644 kexgsss.c 67 create mode 100644 kexgsss.c
65 68
66diff --git a/ChangeLog.gssapi b/ChangeLog.gssapi
67new file mode 100644
68index 000000000..f117a336a
69--- /dev/null
70+++ b/ChangeLog.gssapi
71@@ -0,0 +1,113 @@
72+20110101
73+ - Finally update for OpenSSH 5.6p1
74+ - Add GSSAPIServerIdentity option from Jim Basney
75+
76+20100308
77+ - [ Makefile.in, key.c, key.h ]
78+ Updates for OpenSSH 5.4p1
79+ - [ servconf.c ]
80+ Include GSSAPI options in the sshd -T configuration dump, and flag
81+ some older configuration options as being unsupported. Thanks to Colin
82+ Watson.
83+ -
84+
85+20100124
86+ - [ sshconnect2.c ]
87+ Adapt to deal with additional element in Authmethod structure. Thanks to
88+ Colin Watson
89+
90+20090615
91+ - [ gss-genr.c gss-serv.c kexgssc.c kexgsss.c monitor.c sshconnect2.c
92+ sshd.c ]
93+ Fix issues identified by Greg Hudson following a code review
94+ Check return value of gss_indicate_mechs
95+ Protect GSSAPI calls in monitor, so they can only be used if enabled
96+ Check return values of bignum functions in key exchange
97+ Use BN_clear_free to clear other side's DH value
98+ Make ssh_gssapi_id_kex more robust
99+ Only configure kex table pointers if GSSAPI is enabled
100+ Don't leak mechanism list, or gss mechanism list
101+ Cast data.length before printing
102+ If serverkey isn't provided, use an empty string, rather than NULL
103+
104+20090201
105+ - [ gss-genr.c gss-serv.c kex.h kexgssc.c readconf.c readconf.h ssh-gss.h
106+ ssh_config.5 sshconnet2.c ]
107+ Add support for the GSSAPIClientIdentity option, which allows the user
108+ to specify which GSSAPI identity to use to contact a given server
109+
110+20080404
111+ - [ gss-serv.c ]
112+ Add code to actually implement GSSAPIStrictAcceptCheck, which had somehow
113+ been omitted from a previous version of this patch. Reported by Borislav
114+ Stoichkov
115+
116+20070317
117+ - [ gss-serv-krb5.c ]
118+ Remove C99ism, where new_ccname was being declared in the middle of a
119+ function
120+
121+20061220
122+ - [ servconf.c ]
123+ Make default for GSSAPIStrictAcceptorCheck be Yes, to match previous, and
124+ documented, behaviour. Reported by Dan Watson.
125+
126+20060910
127+ - [ gss-genr.c kexgssc.c kexgsss.c kex.h monitor.c sshconnect2.c sshd.c
128+ ssh-gss.h ]
129+ add support for gss-group14-sha1 key exchange mechanisms
130+ - [ gss-serv.c servconf.c servconf.h sshd_config sshd_config.5 ]
131+ Add GSSAPIStrictAcceptorCheck option to allow the disabling of
132+ acceptor principal checking on multi-homed machines.
133+ <Bugzilla #928>
134+ - [ sshd_config ssh_config ]
135+ Add settings for GSSAPIKeyExchange and GSSAPITrustDNS to the sample
136+ configuration files
137+ - [ kexgss.c kegsss.c sshconnect2.c sshd.c ]
138+ Code cleanup. Replace strlen/xmalloc/snprintf sequences with xasprintf()
139+ Limit length of error messages displayed by client
140+
141+20060909
142+ - [ gss-genr.c gss-serv.c ]
143+ move ssh_gssapi_acquire_cred() and ssh_gssapi_server_ctx to be server
144+ only, where they belong
145+ <Bugzilla #1225>
146+
147+20060829
148+ - [ gss-serv-krb5.c ]
149+ Fix CCAPI credentials cache name when creating KRB5CCNAME environment
150+ variable
151+
152+20060828
153+ - [ gss-genr.c ]
154+ Avoid Heimdal context freeing problem
155+ <Fixed upstream 20060829>
156+
157+20060818
158+ - [ gss-genr.c ssh-gss.h sshconnect2.c ]
159+ Make sure that SPENGO is disabled
160+ <Bugzilla #1218 - Fixed upstream 20060818>
161+
162+20060421
163+ - [ gssgenr.c, sshconnect2.c ]
164+ a few type changes (signed versus unsigned, int versus size_t) to
165+ fix compiler errors/warnings
166+ (from jbasney AT ncsa.uiuc.edu)
167+ - [ kexgssc.c, sshconnect2.c ]
168+ fix uninitialized variable warnings
169+ (from jbasney AT ncsa.uiuc.edu)
170+ - [ gssgenr.c ]
171+ pass oid to gss_display_status (helpful when using GSSAPI mechglue)
172+ (from jbasney AT ncsa.uiuc.edu)
173+ <Bugzilla #1220 >
174+ - [ gss-serv-krb5.c ]
175+ #ifdef HAVE_GSSAPI_KRB5 should be #ifdef HAVE_GSSAPI_KRB5_H
176+ (from jbasney AT ncsa.uiuc.edu)
177+ <Fixed upstream 20060304>
178+ - [ readconf.c, readconf.h, ssh_config.5, sshconnect2.c
179+ add client-side GssapiKeyExchange option
180+ (from jbasney AT ncsa.uiuc.edu)
181+ - [ sshconnect2.c ]
182+ add support for GssapiTrustDns option for gssapi-with-mic
183+ (from jbasney AT ncsa.uiuc.edu)
184+ <gssapi-with-mic support is Bugzilla #1008>
185diff --git a/Makefile.in b/Makefile.in 69diff --git a/Makefile.in b/Makefile.in
186index 126b2c742..70050ffb6 100644 70index 6f001bb36..c31821acc 100644
187--- a/Makefile.in 71--- a/Makefile.in
188+++ b/Makefile.in 72+++ b/Makefile.in
189@@ -100,6 +100,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \ 73@@ -100,6 +100,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \
190 kex.o kexdh.o kexgex.o kexecdh.o kexc25519.o \ 74 kex.o kexdh.o kexgex.o kexecdh.o kexc25519.o \
191 kexdhc.o kexgexc.o kexecdhc.o kexc25519c.o \ 75 kexgexc.o kexgexs.o \
192 kexdhs.o kexgexs.o kexecdhs.o kexc25519s.o \ 76 sntrup4591761.o kexsntrup4591761x25519.o kexgen.o \
193+ kexgssc.o \ 77+ kexgssc.o \
194 platform-pledge.o platform-tracing.o platform-misc.o 78 platform-pledge.o platform-tracing.o platform-misc.o
195 79
196 SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \ 80
197@@ -113,7 +114,7 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o \ 81@@ -114,7 +115,7 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o \
198 auth-bsdauth.o auth2-hostbased.o auth2-kbdint.o \ 82 auth-bsdauth.o auth2-hostbased.o auth2-kbdint.o \
199 auth2-none.o auth2-passwd.o auth2-pubkey.o \ 83 auth2-none.o auth2-passwd.o auth2-pubkey.o \
200 monitor.o monitor_wrap.o auth-krb5.o \ 84 monitor.o monitor_wrap.o auth-krb5.o \
@@ -255,7 +139,7 @@ index 3096f1c8e..204752e1b 100644
255 return (krb5_cc_resolve(ctx, ccname, ccache)); 139 return (krb5_cc_resolve(ctx, ccname, ccache));
256 } 140 }
257diff --git a/auth.c b/auth.c 141diff --git a/auth.c b/auth.c
258index 3ca3762cc..d8e6b4a3d 100644 142index 8696f258e..f7a23afba 100644
259--- a/auth.c 143--- a/auth.c
260+++ b/auth.c 144+++ b/auth.c
261@@ -399,7 +399,8 @@ auth_root_allowed(struct ssh *ssh, const char *method) 145@@ -399,7 +399,8 @@ auth_root_allowed(struct ssh *ssh, const char *method)
@@ -268,7 +152,7 @@ index 3ca3762cc..d8e6b4a3d 100644
268 return 1; 152 return 1;
269 break; 153 break;
270 case PERMIT_FORCED_ONLY: 154 case PERMIT_FORCED_ONLY:
271@@ -737,99 +738,6 @@ fakepw(void) 155@@ -723,99 +724,6 @@ fakepw(void)
272 return (&fake); 156 return (&fake);
273 } 157 }
274 158
@@ -369,7 +253,7 @@ index 3ca3762cc..d8e6b4a3d 100644
369 * Return the canonical name of the host in the other side of the current 253 * Return the canonical name of the host in the other side of the current
370 * connection. The host name is cached, so it is efficient to call this 254 * connection. The host name is cached, so it is efficient to call this
371diff --git a/auth2-gss.c b/auth2-gss.c 255diff --git a/auth2-gss.c b/auth2-gss.c
372index 9351e0428..1f12bb113 100644 256index 9351e0428..d6446c0cf 100644
373--- a/auth2-gss.c 257--- a/auth2-gss.c
374+++ b/auth2-gss.c 258+++ b/auth2-gss.c
375@@ -1,7 +1,7 @@ 259@@ -1,7 +1,7 @@
@@ -381,11 +265,11 @@ index 9351e0428..1f12bb113 100644
381 * 265 *
382 * Redistribution and use in source and binary forms, with or without 266 * Redistribution and use in source and binary forms, with or without
383 * modification, are permitted provided that the following conditions 267 * modification, are permitted provided that the following conditions
384@@ -54,6 +54,46 @@ static int input_gssapi_mic(int type, u_int32_t plen, struct ssh *ssh); 268@@ -54,6 +54,48 @@ static int input_gssapi_mic(int type, u_int32_t plen, struct ssh *ssh);
385 static int input_gssapi_exchange_complete(int type, u_int32_t plen, struct ssh *ssh); 269 static int input_gssapi_exchange_complete(int type, u_int32_t plen, struct ssh *ssh);
386 static int input_gssapi_errtok(int, u_int32_t, struct ssh *); 270 static int input_gssapi_errtok(int, u_int32_t, struct ssh *);
387 271
388+/* 272+/*
389+ * The 'gssapi_keyex' userauth mechanism. 273+ * The 'gssapi_keyex' userauth mechanism.
390+ */ 274+ */
391+static int 275+static int
@@ -393,7 +277,7 @@ index 9351e0428..1f12bb113 100644
393+{ 277+{
394+ Authctxt *authctxt = ssh->authctxt; 278+ Authctxt *authctxt = ssh->authctxt;
395+ int r, authenticated = 0; 279+ int r, authenticated = 0;
396+ struct sshbuf *b; 280+ struct sshbuf *b = NULL;
397+ gss_buffer_desc mic, gssbuf; 281+ gss_buffer_desc mic, gssbuf;
398+ u_char *p; 282+ u_char *p;
399+ size_t len; 283+ size_t len;
@@ -401,8 +285,10 @@ index 9351e0428..1f12bb113 100644
401+ if ((r = sshpkt_get_string(ssh, &p, &len)) != 0 || 285+ if ((r = sshpkt_get_string(ssh, &p, &len)) != 0 ||
402+ (r = sshpkt_get_end(ssh)) != 0) 286+ (r = sshpkt_get_end(ssh)) != 0)
403+ fatal("%s: %s", __func__, ssh_err(r)); 287+ fatal("%s: %s", __func__, ssh_err(r));
288+
404+ if ((b = sshbuf_new()) == NULL) 289+ if ((b = sshbuf_new()) == NULL)
405+ fatal("%s: sshbuf_new failed", __func__); 290+ fatal("%s: sshbuf_new failed", __func__);
291+
406+ mic.value = p; 292+ mic.value = p;
407+ mic.length = len; 293+ mic.length = len;
408+ 294+
@@ -414,11 +300,11 @@ index 9351e0428..1f12bb113 100644
414+ gssbuf.length = sshbuf_len(b); 300+ gssbuf.length = sshbuf_len(b);
415+ 301+
416+ /* gss_kex_context is NULL with privsep, so we can't check it here */ 302+ /* gss_kex_context is NULL with privsep, so we can't check it here */
417+ if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gss_kex_context, 303+ if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gss_kex_context,
418+ &gssbuf, &mic)))) 304+ &gssbuf, &mic))))
419+ authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user, 305+ authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user,
420+ authctxt->pw)); 306+ authctxt->pw, 1));
421+ 307+
422+ sshbuf_free(b); 308+ sshbuf_free(b);
423+ free(mic.value); 309+ free(mic.value);
424+ 310+
@@ -428,27 +314,27 @@ index 9351e0428..1f12bb113 100644
428 /* 314 /*
429 * We only support those mechanisms that we know about (ie ones that we know 315 * We only support those mechanisms that we know about (ie ones that we know
430 * how to check local user kuserok and the like) 316 * how to check local user kuserok and the like)
431@@ -260,7 +300,8 @@ input_gssapi_exchange_complete(int type, u_int32_t plen, struct ssh *ssh) 317@@ -260,7 +302,8 @@ input_gssapi_exchange_complete(int type, u_int32_t plen, struct ssh *ssh)
432 if ((r = sshpkt_get_end(ssh)) != 0) 318 if ((r = sshpkt_get_end(ssh)) != 0)
433 fatal("%s: %s", __func__, ssh_err(r)); 319 fatal("%s: %s", __func__, ssh_err(r));
434 320
435- authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user)); 321- authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user));
436+ authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user, 322+ authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user,
437+ authctxt->pw)); 323+ authctxt->pw, 1));
438 324
439 if ((!use_privsep || mm_is_monitor()) && 325 if ((!use_privsep || mm_is_monitor()) &&
440 (displayname = ssh_gssapi_displayname()) != NULL) 326 (displayname = ssh_gssapi_displayname()) != NULL)
441@@ -306,7 +347,8 @@ input_gssapi_mic(int type, u_int32_t plen, struct ssh *ssh) 327@@ -306,7 +349,8 @@ input_gssapi_mic(int type, u_int32_t plen, struct ssh *ssh)
442 gssbuf.length = sshbuf_len(b); 328 gssbuf.length = sshbuf_len(b);
443 329
444 if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gssctxt, &gssbuf, &mic)))) 330 if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gssctxt, &gssbuf, &mic))))
445- authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user)); 331- authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user));
446+ authenticated = 332+ authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user,
447+ PRIVSEP(ssh_gssapi_userok(authctxt->user, authctxt->pw)); 333+ authctxt->pw, 0));
448 else 334 else
449 logit("GSSAPI MIC check failed"); 335 logit("GSSAPI MIC check failed");
450 336
451@@ -326,6 +368,12 @@ input_gssapi_mic(int type, u_int32_t plen, struct ssh *ssh) 337@@ -326,6 +370,12 @@ input_gssapi_mic(int type, u_int32_t plen, struct ssh *ssh)
452 return 0; 338 return 0;
453 } 339 }
454 340
@@ -462,10 +348,10 @@ index 9351e0428..1f12bb113 100644
462 "gssapi-with-mic", 348 "gssapi-with-mic",
463 userauth_gssapi, 349 userauth_gssapi,
464diff --git a/auth2.c b/auth2.c 350diff --git a/auth2.c b/auth2.c
465index 4d19957a6..a77742819 100644 351index 16ae1a363..7417eafa4 100644
466--- a/auth2.c 352--- a/auth2.c
467+++ b/auth2.c 353+++ b/auth2.c
468@@ -74,6 +74,7 @@ extern Authmethod method_passwd; 354@@ -75,6 +75,7 @@ extern Authmethod method_passwd;
469 extern Authmethod method_kbdint; 355 extern Authmethod method_kbdint;
470 extern Authmethod method_hostbased; 356 extern Authmethod method_hostbased;
471 #ifdef GSSAPI 357 #ifdef GSSAPI
@@ -473,7 +359,7 @@ index 4d19957a6..a77742819 100644
473 extern Authmethod method_gssapi; 359 extern Authmethod method_gssapi;
474 #endif 360 #endif
475 361
476@@ -81,6 +82,7 @@ Authmethod *authmethods[] = { 362@@ -82,6 +83,7 @@ Authmethod *authmethods[] = {
477 &method_none, 363 &method_none,
478 &method_pubkey, 364 &method_pubkey,
479 #ifdef GSSAPI 365 #ifdef GSSAPI
@@ -600,7 +486,7 @@ index 26d62855a..0cadc9f18 100644
600 int get_peer_port(int); 486 int get_peer_port(int);
601 char *get_local_ipaddr(int); 487 char *get_local_ipaddr(int);
602diff --git a/clientloop.c b/clientloop.c 488diff --git a/clientloop.c b/clientloop.c
603index 8d312cdaa..1464634b0 100644 489index 086c0dfe8..9b90c64f3 100644
604--- a/clientloop.c 490--- a/clientloop.c
605+++ b/clientloop.c 491+++ b/clientloop.c
606@@ -112,6 +112,10 @@ 492@@ -112,6 +112,10 @@
@@ -614,7 +500,7 @@ index 8d312cdaa..1464634b0 100644
614 /* import options */ 500 /* import options */
615 extern Options options; 501 extern Options options;
616 502
617@@ -1370,9 +1374,18 @@ client_loop(struct ssh *ssh, int have_pty, int escape_char_arg, 503@@ -1374,9 +1378,18 @@ client_loop(struct ssh *ssh, int have_pty, int escape_char_arg,
618 break; 504 break;
619 505
620 /* Do channel operations unless rekeying in progress. */ 506 /* Do channel operations unless rekeying in progress. */
@@ -632,37 +518,13 @@ index 8d312cdaa..1464634b0 100644
632+ } 518+ }
633+ 519+
634 /* Buffer input from the connection. */ 520 /* Buffer input from the connection. */
635 client_process_net_input(readset); 521 client_process_net_input(ssh, readset);
636
637diff --git a/config.h.in b/config.h.in
638index 91b65db8f..209760c7c 100644
639--- a/config.h.in
640+++ b/config.h.in
641@@ -1845,6 +1845,9 @@
642 /* Use btmp to log bad logins */
643 #undef USE_BTMP
644
645+/* platform uses an in-memory credentials cache */
646+#undef USE_CCAPI
647+
648 /* Use libedit for sftp */
649 #undef USE_LIBEDIT
650
651@@ -1860,6 +1863,9 @@
652 /* Use PIPES instead of a socketpair() */
653 #undef USE_PIPES
654
655+/* platform has the Security Authorization Session API */
656+#undef USE_SECURITY_SESSION_API
657+
658 /* Define if you have Solaris privileges */
659 #undef USE_SOLARIS_PRIVS
660 522
661diff --git a/configure.ac b/configure.ac 523diff --git a/configure.ac b/configure.ac
662index 7379ab358..023e7cc55 100644 524index 30be6c182..2869f7042 100644
663--- a/configure.ac 525--- a/configure.ac
664+++ b/configure.ac 526+++ b/configure.ac
665@@ -664,6 +664,30 @@ main() { if (NSVersionOfRunTimeLibrary("System") >= (60 << 16)) 527@@ -665,6 +665,30 @@ main() { if (NSVersionOfRunTimeLibrary("System") >= (60 << 16))
666 [Use tunnel device compatibility to OpenBSD]) 528 [Use tunnel device compatibility to OpenBSD])
667 AC_DEFINE([SSH_TUN_PREPEND_AF], [1], 529 AC_DEFINE([SSH_TUN_PREPEND_AF], [1],
668 [Prepend the address family to IP tunnel traffic]) 530 [Prepend the address family to IP tunnel traffic])
@@ -670,7 +532,7 @@ index 7379ab358..023e7cc55 100644
670+ AC_TRY_COMPILE([#include <Security/AuthSession.h>], 532+ AC_TRY_COMPILE([#include <Security/AuthSession.h>],
671+ [SessionCreate(0, 0);], 533+ [SessionCreate(0, 0);],
672+ [ac_cv_use_security_session_api="yes" 534+ [ac_cv_use_security_session_api="yes"
673+ AC_DEFINE([USE_SECURITY_SESSION_API], [1], 535+ AC_DEFINE([USE_SECURITY_SESSION_API], [1],
674+ [platform has the Security Authorization Session API]) 536+ [platform has the Security Authorization Session API])
675+ LIBS="$LIBS -framework Security" 537+ LIBS="$LIBS -framework Security"
676+ AC_MSG_RESULT([yes])], 538+ AC_MSG_RESULT([yes])],
@@ -681,7 +543,7 @@ index 7379ab358..023e7cc55 100644
681+ [#include <Kerberos/Kerberos.h>], 543+ [#include <Kerberos/Kerberos.h>],
682+ [cc_context_t c; 544+ [cc_context_t c;
683+ (void) cc_initialize (&c, 0, NULL, NULL);], 545+ (void) cc_initialize (&c, 0, NULL, NULL);],
684+ [AC_DEFINE([USE_CCAPI], [1], 546+ [AC_DEFINE([USE_CCAPI], [1],
685+ [platform uses an in-memory credentials cache]) 547+ [platform uses an in-memory credentials cache])
686+ LIBS="$LIBS -framework Security" 548+ LIBS="$LIBS -framework Security"
687+ AC_MSG_RESULT([yes]) 549+ AC_MSG_RESULT([yes])
@@ -694,7 +556,7 @@ index 7379ab358..023e7cc55 100644
694 AC_CHECK_DECL([AU_IPv4], [], 556 AC_CHECK_DECL([AU_IPv4], [],
695 AC_DEFINE([AU_IPv4], [0], [System only supports IPv4 audit records]) 557 AC_DEFINE([AU_IPv4], [0], [System only supports IPv4 audit records])
696diff --git a/gss-genr.c b/gss-genr.c 558diff --git a/gss-genr.c b/gss-genr.c
697index d56257b4a..491e62cee 100644 559index d56257b4a..763a63ffa 100644
698--- a/gss-genr.c 560--- a/gss-genr.c
699+++ b/gss-genr.c 561+++ b/gss-genr.c
700@@ -1,7 +1,7 @@ 562@@ -1,7 +1,7 @@
@@ -706,16 +568,15 @@ index d56257b4a..491e62cee 100644
706 * 568 *
707 * Redistribution and use in source and binary forms, with or without 569 * Redistribution and use in source and binary forms, with or without
708 * modification, are permitted provided that the following conditions 570 * modification, are permitted provided that the following conditions
709@@ -39,14 +39,37 @@ 571@@ -41,12 +41,36 @@
710 #include "xmalloc.h"
711 #include "ssherr.h"
712 #include "sshbuf.h" 572 #include "sshbuf.h"
713+#include "sshkey.h"
714 #include "log.h" 573 #include "log.h"
715 #include "ssh2.h" 574 #include "ssh2.h"
716+#include "cipher.h" 575+#include "cipher.h"
576+#include "sshkey.h"
717+#include "kex.h" 577+#include "kex.h"
718+#include "digest.h" 578+#include "digest.h"
579+#include "packet.h"
719 580
720 #include "ssh-gss.h" 581 #include "ssh-gss.h"
721 582
@@ -736,7 +597,7 @@ index d56257b4a..491e62cee 100644
736+ 597+
737+static ssh_gss_kex_mapping *gss_enc2oid = NULL; 598+static ssh_gss_kex_mapping *gss_enc2oid = NULL;
738+ 599+
739+int 600+int
740+ssh_gssapi_oid_table_ok(void) { 601+ssh_gssapi_oid_table_ok(void) {
741+ return (gss_enc2oid != NULL); 602+ return (gss_enc2oid != NULL);
742+} 603+}
@@ -744,10 +605,25 @@ index d56257b4a..491e62cee 100644
744 /* sshbuf_get for gss_buffer_desc */ 605 /* sshbuf_get for gss_buffer_desc */
745 int 606 int
746 ssh_gssapi_get_buffer_desc(struct sshbuf *b, gss_buffer_desc *g) 607 ssh_gssapi_get_buffer_desc(struct sshbuf *b, gss_buffer_desc *g)
747@@ -62,6 +85,143 @@ ssh_gssapi_get_buffer_desc(struct sshbuf *b, gss_buffer_desc *g) 608@@ -62,6 +86,162 @@ ssh_gssapi_get_buffer_desc(struct sshbuf *b, gss_buffer_desc *g)
748 return 0; 609 return 0;
749 } 610 }
750 611
612+/* sshpkt_get of gss_buffer_desc */
613+int
614+ssh_gssapi_sshpkt_get_buffer_desc(struct ssh *ssh, gss_buffer_desc *g)
615+{
616+ int r;
617+ u_char *p;
618+ size_t len;
619+
620+ if ((r = sshpkt_get_string(ssh, &p, &len)) != 0)
621+ return r;
622+ g->value = p;
623+ g->length = len;
624+ return 0;
625+}
626+
751+/* 627+/*
752+ * Return a list of the gss-group1-sha1 mechanisms supported by this program 628+ * Return a list of the gss-group1-sha1 mechanisms supported by this program
753+ * 629+ *
@@ -756,27 +632,30 @@ index d56257b4a..491e62cee 100644
756+ */ 632+ */
757+ 633+
758+char * 634+char *
759+ssh_gssapi_client_mechanisms(const char *host, const char *client) { 635+ssh_gssapi_client_mechanisms(const char *host, const char *client,
760+ gss_OID_set gss_supported; 636+ const char *kex) {
637+ gss_OID_set gss_supported = NULL;
761+ OM_uint32 min_status; 638+ OM_uint32 min_status;
762+ 639+
763+ if (GSS_ERROR(gss_indicate_mechs(&min_status, &gss_supported))) 640+ if (GSS_ERROR(gss_indicate_mechs(&min_status, &gss_supported)))
764+ return NULL; 641+ return NULL;
765+ 642+
766+ return(ssh_gssapi_kex_mechs(gss_supported, ssh_gssapi_check_mechanism, 643+ return ssh_gssapi_kex_mechs(gss_supported, ssh_gssapi_check_mechanism,
767+ host, client)); 644+ host, client, kex);
768+} 645+}
769+ 646+
770+char * 647+char *
771+ssh_gssapi_kex_mechs(gss_OID_set gss_supported, ssh_gssapi_check_fn *check, 648+ssh_gssapi_kex_mechs(gss_OID_set gss_supported, ssh_gssapi_check_fn *check,
772+ const char *host, const char *client) { 649+ const char *host, const char *client, const char *kex) {
773+ struct sshbuf *buf; 650+ struct sshbuf *buf = NULL;
774+ size_t i; 651+ size_t i;
775+ int r, oidpos, enclen; 652+ int r = SSH_ERR_ALLOC_FAIL;
653+ int oidpos, enclen;
776+ char *mechs, *encoded; 654+ char *mechs, *encoded;
777+ u_char digest[SSH_DIGEST_MAX_LENGTH]; 655+ u_char digest[SSH_DIGEST_MAX_LENGTH];
778+ char deroid[2]; 656+ char deroid[2];
779+ struct ssh_digest_ctx *md; 657+ struct ssh_digest_ctx *md = NULL;
658+ char *s, *cp, *p;
780+ 659+
781+ if (gss_enc2oid != NULL) { 660+ if (gss_enc2oid != NULL) {
782+ for (i = 0; gss_enc2oid[i].encoded != NULL; i++) 661+ for (i = 0; gss_enc2oid[i].encoded != NULL; i++)
@@ -791,6 +670,7 @@ index d56257b4a..491e62cee 100644
791+ fatal("%s: sshbuf_new failed", __func__); 670+ fatal("%s: sshbuf_new failed", __func__);
792+ 671+
793+ oidpos = 0; 672+ oidpos = 0;
673+ s = cp = xstrdup(kex);
794+ for (i = 0; i < gss_supported->count; i++) { 674+ for (i = 0; i < gss_supported->count; i++) {
795+ if (gss_supported->elements[i].length < 128 && 675+ if (gss_supported->elements[i].length < 128 &&
796+ (*check)(NULL, &(gss_supported->elements[i]), host, client)) { 676+ (*check)(NULL, &(gss_supported->elements[i]), host, client)) {
@@ -799,12 +679,15 @@ index d56257b4a..491e62cee 100644
799+ deroid[1] = gss_supported->elements[i].length; 679+ deroid[1] = gss_supported->elements[i].length;
800+ 680+
801+ if ((md = ssh_digest_start(SSH_DIGEST_MD5)) == NULL || 681+ if ((md = ssh_digest_start(SSH_DIGEST_MD5)) == NULL ||
802+ ssh_digest_update(md, deroid, 2) != 0 || 682+ (r = ssh_digest_update(md, deroid, 2)) != 0 ||
803+ ssh_digest_update(md, 683+ (r = ssh_digest_update(md,
804+ gss_supported->elements[i].elements, 684+ gss_supported->elements[i].elements,
805+ gss_supported->elements[i].length) != 0 || 685+ gss_supported->elements[i].length)) != 0 ||
806+ ssh_digest_final(md, digest, sizeof(digest)) != 0) 686+ (r = ssh_digest_final(md, digest, sizeof(digest))) != 0)
807+ fatal("%s: digest failed", __func__); 687+ fatal("%s: digest failed: %s", __func__,
688+ ssh_err(r));
689+ ssh_digest_free(md);
690+ md = NULL;
808+ 691+
809+ encoded = xmalloc(ssh_digest_bytes(SSH_DIGEST_MD5) 692+ encoded = xmalloc(ssh_digest_bytes(SSH_DIGEST_MD5)
810+ * 2); 693+ * 2);
@@ -812,69 +695,66 @@ index d56257b4a..491e62cee 100644
812+ ssh_digest_bytes(SSH_DIGEST_MD5), encoded, 695+ ssh_digest_bytes(SSH_DIGEST_MD5), encoded,
813+ ssh_digest_bytes(SSH_DIGEST_MD5) * 2); 696+ ssh_digest_bytes(SSH_DIGEST_MD5) * 2);
814+ 697+
815+ if (oidpos != 0) { 698+ cp = strncpy(s, kex, strlen(kex));
816+ if ((r = sshbuf_put_u8(buf, ',')) != 0) 699+ for ((p = strsep(&cp, ",")); p && *p != '\0';
817+ fatal("%s: buffer error: %s", 700+ (p = strsep(&cp, ","))) {
701+ if (sshbuf_len(buf) != 0 &&
702+ (r = sshbuf_put_u8(buf, ',')) != 0)
703+ fatal("%s: sshbuf_put_u8 error: %s",
704+ __func__, ssh_err(r));
705+ if ((r = sshbuf_put(buf, p, strlen(p))) != 0 ||
706+ (r = sshbuf_put(buf, encoded, enclen)) != 0)
707+ fatal("%s: sshbuf_put error: %s",
818+ __func__, ssh_err(r)); 708+ __func__, ssh_err(r));
819+ } 709+ }
820+ 710+
821+ if ((r = sshbuf_put(buf, KEX_GSS_GEX_SHA1_ID,
822+ sizeof(KEX_GSS_GEX_SHA1_ID) - 1)) != 0 ||
823+ (r = sshbuf_put(buf, encoded, enclen)) != 0 ||
824+ (r = sshbuf_put_u8(buf, ',')) != 0 ||
825+ (r = sshbuf_put(buf, KEX_GSS_GRP1_SHA1_ID,
826+ sizeof(KEX_GSS_GRP1_SHA1_ID) - 1)) != 0 ||
827+ (r = sshbuf_put(buf, encoded, enclen)) != 0 ||
828+ (r = sshbuf_put_u8(buf, ',')) != 0 ||
829+ (r = sshbuf_put(buf, KEX_GSS_GRP14_SHA1_ID,
830+ sizeof(KEX_GSS_GRP14_SHA1_ID) - 1)) != 0 ||
831+ (r = sshbuf_put(buf, encoded, enclen)) != 0)
832+ fatal("%s: buffer error: %s",
833+ __func__, ssh_err(r));
834+
835+ gss_enc2oid[oidpos].oid = &(gss_supported->elements[i]); 711+ gss_enc2oid[oidpos].oid = &(gss_supported->elements[i]);
836+ gss_enc2oid[oidpos].encoded = encoded; 712+ gss_enc2oid[oidpos].encoded = encoded;
837+ oidpos++; 713+ oidpos++;
838+ } 714+ }
839+ } 715+ }
716+ free(s);
840+ gss_enc2oid[oidpos].oid = NULL; 717+ gss_enc2oid[oidpos].oid = NULL;
841+ gss_enc2oid[oidpos].encoded = NULL; 718+ gss_enc2oid[oidpos].encoded = NULL;
842+ 719+
843+ if ((mechs = sshbuf_dup_string(buf)) == NULL) 720+ if ((mechs = sshbuf_dup_string(buf)) == NULL)
844+ fatal("%s: sshbuf_dup_string failed", __func__); 721+ fatal("%s: sshbuf_dup_string failed", __func__);
845+ 722+
723+ sshbuf_free(buf);
724+
846+ if (strlen(mechs) == 0) { 725+ if (strlen(mechs) == 0) {
847+ free(mechs); 726+ free(mechs);
848+ mechs = NULL; 727+ mechs = NULL;
849+ } 728+ }
850+ 729+
851+ return (mechs); 730+ return (mechs);
852+} 731+}
853+ 732+
854+gss_OID 733+gss_OID
855+ssh_gssapi_id_kex(Gssctxt *ctx, char *name, int kex_type) { 734+ssh_gssapi_id_kex(Gssctxt *ctx, char *name, int kex_type) {
856+ int i = 0; 735+ int i = 0;
857+ 736+
858+ switch (kex_type) { 737+#define SKIP_KEX_NAME(type) \
859+ case KEX_GSS_GRP1_SHA1: 738+ case type: \
860+ if (strlen(name) < sizeof(KEX_GSS_GRP1_SHA1_ID)) 739+ if (strlen(name) < sizeof(type##_ID)) \
861+ return GSS_C_NO_OID; 740+ return GSS_C_NO_OID; \
862+ name += sizeof(KEX_GSS_GRP1_SHA1_ID) - 1; 741+ name += sizeof(type##_ID) - 1; \
863+ break;
864+ case KEX_GSS_GRP14_SHA1:
865+ if (strlen(name) < sizeof(KEX_GSS_GRP14_SHA1_ID))
866+ return GSS_C_NO_OID;
867+ name += sizeof(KEX_GSS_GRP14_SHA1_ID) - 1;
868+ break;
869+ case KEX_GSS_GEX_SHA1:
870+ if (strlen(name) < sizeof(KEX_GSS_GEX_SHA1_ID))
871+ return GSS_C_NO_OID;
872+ name += sizeof(KEX_GSS_GEX_SHA1_ID) - 1;
873+ break; 742+ break;
743+
744+ switch (kex_type) {
745+ SKIP_KEX_NAME(KEX_GSS_GRP1_SHA1)
746+ SKIP_KEX_NAME(KEX_GSS_GRP14_SHA1)
747+ SKIP_KEX_NAME(KEX_GSS_GRP14_SHA256)
748+ SKIP_KEX_NAME(KEX_GSS_GRP16_SHA512)
749+ SKIP_KEX_NAME(KEX_GSS_GEX_SHA1)
750+ SKIP_KEX_NAME(KEX_GSS_NISTP256_SHA256)
751+ SKIP_KEX_NAME(KEX_GSS_C25519_SHA256)
874+ default: 752+ default:
875+ return GSS_C_NO_OID; 753+ return GSS_C_NO_OID;
876+ } 754+ }
877+ 755+
756+#undef SKIP_KEX_NAME
757+
878+ while (gss_enc2oid[i].encoded != NULL && 758+ while (gss_enc2oid[i].encoded != NULL &&
879+ strcmp(name, gss_enc2oid[i].encoded) != 0) 759+ strcmp(name, gss_enc2oid[i].encoded) != 0)
880+ i++; 760+ i++;
@@ -888,7 +768,7 @@ index d56257b4a..491e62cee 100644
888 /* Check that the OID in a data stream matches that in the context */ 768 /* Check that the OID in a data stream matches that in the context */
889 int 769 int
890 ssh_gssapi_check_oid(Gssctxt *ctx, void *data, size_t len) 770 ssh_gssapi_check_oid(Gssctxt *ctx, void *data, size_t len)
891@@ -218,7 +378,7 @@ ssh_gssapi_init_ctx(Gssctxt *ctx, int deleg_creds, gss_buffer_desc *recv_tok, 771@@ -218,7 +398,7 @@ ssh_gssapi_init_ctx(Gssctxt *ctx, int deleg_creds, gss_buffer_desc *recv_tok,
892 } 772 }
893 773
894 ctx->major = gss_init_sec_context(&ctx->minor, 774 ctx->major = gss_init_sec_context(&ctx->minor,
@@ -897,7 +777,7 @@ index d56257b4a..491e62cee 100644
897 GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG | deleg_flag, 777 GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG | deleg_flag,
898 0, NULL, recv_tok, NULL, send_tok, flags, NULL); 778 0, NULL, recv_tok, NULL, send_tok, flags, NULL);
899 779
900@@ -247,9 +407,43 @@ ssh_gssapi_import_name(Gssctxt *ctx, const char *host) 780@@ -247,9 +427,43 @@ ssh_gssapi_import_name(Gssctxt *ctx, const char *host)
901 return (ctx->major); 781 return (ctx->major);
902 } 782 }
903 783
@@ -919,8 +799,8 @@ index d56257b4a..491e62cee 100644
919+ GSS_C_NT_USER_NAME, &gssname); 799+ GSS_C_NT_USER_NAME, &gssname);
920+ 800+
921+ if (!ctx->major) 801+ if (!ctx->major)
922+ ctx->major = gss_acquire_cred(&ctx->minor, 802+ ctx->major = gss_acquire_cred(&ctx->minor,
923+ gssname, 0, oidset, GSS_C_INITIATE, 803+ gssname, 0, oidset, GSS_C_INITIATE,
924+ &ctx->client_creds, NULL, NULL); 804+ &ctx->client_creds, NULL, NULL);
925+ 805+
926+ gss_release_name(&status, &gssname); 806+ gss_release_name(&status, &gssname);
@@ -935,13 +815,13 @@ index d56257b4a..491e62cee 100644
935 OM_uint32 815 OM_uint32
936 ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash) 816 ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash)
937 { 817 {
938+ if (ctx == NULL) 818+ if (ctx == NULL)
939+ return -1; 819+ return -1;
940+ 820+
941 if ((ctx->major = gss_get_mic(&ctx->minor, ctx->context, 821 if ((ctx->major = gss_get_mic(&ctx->minor, ctx->context,
942 GSS_C_QOP_DEFAULT, buffer, hash))) 822 GSS_C_QOP_DEFAULT, buffer, hash)))
943 ssh_gssapi_error(ctx); 823 ssh_gssapi_error(ctx);
944@@ -257,6 +451,19 @@ ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash) 824@@ -257,6 +471,19 @@ ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash)
945 return (ctx->major); 825 return (ctx->major);
946 } 826 }
947 827
@@ -961,12 +841,12 @@ index d56257b4a..491e62cee 100644
961 void 841 void
962 ssh_gssapi_buildmic(struct sshbuf *b, const char *user, const char *service, 842 ssh_gssapi_buildmic(struct sshbuf *b, const char *user, const char *service,
963 const char *context) 843 const char *context)
964@@ -273,11 +480,16 @@ ssh_gssapi_buildmic(struct sshbuf *b, const char *user, const char *service, 844@@ -273,11 +500,16 @@ ssh_gssapi_buildmic(struct sshbuf *b, const char *user, const char *service,
965 } 845 }
966 846
967 int 847 int
968-ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host) 848-ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host)
969+ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host, 849+ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host,
970+ const char *client) 850+ const char *client)
971 { 851 {
972 gss_buffer_desc token = GSS_C_EMPTY_BUFFER; 852 gss_buffer_desc token = GSS_C_EMPTY_BUFFER;
@@ -979,7 +859,7 @@ index d56257b4a..491e62cee 100644
979 859
980 /* RFC 4462 says we MUST NOT do SPNEGO */ 860 /* RFC 4462 says we MUST NOT do SPNEGO */
981 if (oid->length == spnego_oid.length && 861 if (oid->length == spnego_oid.length &&
982@@ -287,6 +499,10 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host) 862@@ -287,6 +519,10 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host)
983 ssh_gssapi_build_ctx(ctx); 863 ssh_gssapi_build_ctx(ctx);
984 ssh_gssapi_set_oid(*ctx, oid); 864 ssh_gssapi_set_oid(*ctx, oid);
985 major = ssh_gssapi_import_name(*ctx, host); 865 major = ssh_gssapi_import_name(*ctx, host);
@@ -990,12 +870,12 @@ index d56257b4a..491e62cee 100644
990 if (!GSS_ERROR(major)) { 870 if (!GSS_ERROR(major)) {
991 major = ssh_gssapi_init_ctx(*ctx, 0, GSS_C_NO_BUFFER, &token, 871 major = ssh_gssapi_init_ctx(*ctx, 0, GSS_C_NO_BUFFER, &token,
992 NULL); 872 NULL);
993@@ -296,10 +512,66 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host) 873@@ -296,10 +532,66 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host)
994 GSS_C_NO_BUFFER); 874 GSS_C_NO_BUFFER);
995 } 875 }
996 876
997- if (GSS_ERROR(major)) 877- if (GSS_ERROR(major))
998+ if (GSS_ERROR(major) || intctx != NULL) 878+ if (GSS_ERROR(major) || intctx != NULL)
999 ssh_gssapi_delete_ctx(ctx); 879 ssh_gssapi_delete_ctx(ctx);
1000 880
1001 return (!GSS_ERROR(major)); 881 return (!GSS_ERROR(major));
@@ -1010,7 +890,7 @@ index d56257b4a..491e62cee 100644
1010+ static OM_uint32 last_call = 0; 890+ static OM_uint32 last_call = 0;
1011+ OM_uint32 lifetime, now, major, minor; 891+ OM_uint32 lifetime, now, major, minor;
1012+ int equal; 892+ int equal;
1013+ 893+
1014+ now = time(NULL); 894+ now = time(NULL);
1015+ 895+
1016+ if (ctxt) { 896+ if (ctxt) {
@@ -1038,8 +918,8 @@ index d56257b4a..491e62cee 100644
1038+ 918+
1039+ if (saved_mech == GSS_C_NO_OID) 919+ if (saved_mech == GSS_C_NO_OID)
1040+ return 0; 920+ return 0;
1041+ 921+
1042+ major = gss_inquire_cred(&minor, GSS_C_NO_CREDENTIAL, 922+ major = gss_inquire_cred(&minor, GSS_C_NO_CREDENTIAL,
1043+ &name, &lifetime, NULL, NULL); 923+ &name, &lifetime, NULL, NULL);
1044+ if (major == GSS_S_CREDENTIALS_EXPIRED) 924+ if (major == GSS_S_CREDENTIALS_EXPIRED)
1045+ return 0; 925+ return 0;
@@ -1059,7 +939,7 @@ index d56257b4a..491e62cee 100644
1059+ 939+
1060 #endif /* GSSAPI */ 940 #endif /* GSSAPI */
1061diff --git a/gss-serv-krb5.c b/gss-serv-krb5.c 941diff --git a/gss-serv-krb5.c b/gss-serv-krb5.c
1062index a151bc1e4..90f8692f5 100644 942index a151bc1e4..ef9beb67c 100644
1063--- a/gss-serv-krb5.c 943--- a/gss-serv-krb5.c
1064+++ b/gss-serv-krb5.c 944+++ b/gss-serv-krb5.c
1065@@ -1,7 +1,7 @@ 945@@ -1,7 +1,7 @@
@@ -1107,7 +987,7 @@ index a151bc1e4..90f8692f5 100644
1107 } 987 }
1108 988
1109+int 989+int
1110+ssh_gssapi_krb5_updatecreds(ssh_gssapi_ccache *store, 990+ssh_gssapi_krb5_updatecreds(ssh_gssapi_ccache *store,
1111+ ssh_gssapi_client *client) 991+ ssh_gssapi_client *client)
1112+{ 992+{
1113+ krb5_ccache ccache = NULL; 993+ krb5_ccache ccache = NULL;
@@ -1116,14 +996,14 @@ index a151bc1e4..90f8692f5 100644
1116+ krb5_error_code problem; 996+ krb5_error_code problem;
1117+ OM_uint32 maj_status, min_status; 997+ OM_uint32 maj_status, min_status;
1118+ 998+
1119+ if ((problem = krb5_cc_resolve(krb_context, store->envval, &ccache))) { 999+ if ((problem = krb5_cc_resolve(krb_context, store->envval, &ccache))) {
1120+ logit("krb5_cc_resolve(): %.100s", 1000+ logit("krb5_cc_resolve(): %.100s",
1121+ krb5_get_err_text(krb_context, problem)); 1001+ krb5_get_err_text(krb_context, problem));
1122+ return 0; 1002+ return 0;
1123+ } 1003+ }
1124+ 1004+
1125+ /* Find out who the principal in this cache is */ 1005+ /* Find out who the principal in this cache is */
1126+ if ((problem = krb5_cc_get_principal(krb_context, ccache, 1006+ if ((problem = krb5_cc_get_principal(krb_context, ccache,
1127+ &principal))) { 1007+ &principal))) {
1128+ logit("krb5_cc_get_principal(): %.100s", 1008+ logit("krb5_cc_get_principal(): %.100s",
1129+ krb5_get_err_text(krb_context, problem)); 1009+ krb5_get_err_text(krb_context, problem));
@@ -1185,7 +1065,7 @@ index a151bc1e4..90f8692f5 100644
1185 1065
1186 #endif /* KRB5 */ 1066 #endif /* KRB5 */
1187diff --git a/gss-serv.c b/gss-serv.c 1067diff --git a/gss-serv.c b/gss-serv.c
1188index ab3a15f0f..6c087a1b1 100644 1068index ab3a15f0f..1d47870e7 100644
1189--- a/gss-serv.c 1069--- a/gss-serv.c
1190+++ b/gss-serv.c 1070+++ b/gss-serv.c
1191@@ -1,7 +1,7 @@ 1071@@ -1,7 +1,7 @@
@@ -1197,7 +1077,7 @@ index ab3a15f0f..6c087a1b1 100644
1197 * 1077 *
1198 * Redistribution and use in source and binary forms, with or without 1078 * Redistribution and use in source and binary forms, with or without
1199 * modification, are permitted provided that the following conditions 1079 * modification, are permitted provided that the following conditions
1200@@ -44,17 +44,22 @@ 1080@@ -44,17 +44,19 @@
1201 #include "session.h" 1081 #include "session.h"
1202 #include "misc.h" 1082 #include "misc.h"
1203 #include "servconf.h" 1083 #include "servconf.h"
@@ -1205,16 +1085,14 @@ index ab3a15f0f..6c087a1b1 100644
1205 1085
1206 #include "ssh-gss.h" 1086 #include "ssh-gss.h"
1207+#include "monitor_wrap.h" 1087+#include "monitor_wrap.h"
1208+
1209+extern ServerOptions options;
1210 1088
1211 extern ServerOptions options; 1089 extern ServerOptions options;
1212 1090
1213 static ssh_gssapi_client gssapi_client = 1091 static ssh_gssapi_client gssapi_client =
1214 { GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER, 1092- { GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER,
1215- GSS_C_NO_CREDENTIAL, NULL, {NULL, NULL, NULL, NULL}}; 1093- GSS_C_NO_CREDENTIAL, NULL, {NULL, NULL, NULL, NULL}};
1216+ GSS_C_NO_CREDENTIAL, GSS_C_NO_NAME, NULL, 1094+ { GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER, GSS_C_NO_CREDENTIAL,
1217+ {NULL, NULL, NULL, NULL, NULL}, 0, 0}; 1095+ GSS_C_NO_NAME, NULL, {NULL, NULL, NULL, NULL, NULL}, 0, 0};
1218 1096
1219 ssh_gssapi_mech gssapi_null_mech = 1097 ssh_gssapi_mech gssapi_null_mech =
1220- { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL}; 1098- { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL};
@@ -1222,7 +1100,7 @@ index ab3a15f0f..6c087a1b1 100644
1222 1100
1223 #ifdef KRB5 1101 #ifdef KRB5
1224 extern ssh_gssapi_mech gssapi_kerberos_mech; 1102 extern ssh_gssapi_mech gssapi_kerberos_mech;
1225@@ -140,6 +145,28 @@ ssh_gssapi_server_ctx(Gssctxt **ctx, gss_OID oid) 1103@@ -140,6 +142,29 @@ ssh_gssapi_server_ctx(Gssctxt **ctx, gss_OID oid)
1226 return (ssh_gssapi_acquire_cred(*ctx)); 1104 return (ssh_gssapi_acquire_cred(*ctx));
1227 } 1105 }
1228 1106
@@ -1232,7 +1110,8 @@ index ab3a15f0f..6c087a1b1 100644
1232+ if (supported_oids == NULL) 1110+ if (supported_oids == NULL)
1233+ ssh_gssapi_prepare_supported_oids(); 1111+ ssh_gssapi_prepare_supported_oids();
1234+ return (ssh_gssapi_kex_mechs(supported_oids, 1112+ return (ssh_gssapi_kex_mechs(supported_oids,
1235+ &ssh_gssapi_server_check_mech, NULL, NULL)); 1113+ &ssh_gssapi_server_check_mech, NULL, NULL,
1114+ options.gss_kex_algorithms));
1236+} 1115+}
1237+ 1116+
1238+/* Unprivileged */ 1117+/* Unprivileged */
@@ -1241,7 +1120,7 @@ index ab3a15f0f..6c087a1b1 100644
1241+ const char *dummy) { 1120+ const char *dummy) {
1242+ Gssctxt *ctx = NULL; 1121+ Gssctxt *ctx = NULL;
1243+ int res; 1122+ int res;
1244+ 1123+
1245+ res = !GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctx, oid))); 1124+ res = !GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctx, oid)));
1246+ ssh_gssapi_delete_ctx(&ctx); 1125+ ssh_gssapi_delete_ctx(&ctx);
1247+ 1126+
@@ -1251,7 +1130,7 @@ index ab3a15f0f..6c087a1b1 100644
1251 /* Unprivileged */ 1130 /* Unprivileged */
1252 void 1131 void
1253 ssh_gssapi_supported_oids(gss_OID_set *oidset) 1132 ssh_gssapi_supported_oids(gss_OID_set *oidset)
1254@@ -150,7 +177,9 @@ ssh_gssapi_supported_oids(gss_OID_set *oidset) 1133@@ -150,7 +175,9 @@ ssh_gssapi_supported_oids(gss_OID_set *oidset)
1255 gss_OID_set supported; 1134 gss_OID_set supported;
1256 1135
1257 gss_create_empty_oid_set(&min_status, oidset); 1136 gss_create_empty_oid_set(&min_status, oidset);
@@ -1262,7 +1141,7 @@ index ab3a15f0f..6c087a1b1 100644
1262 1141
1263 while (supported_mechs[i]->name != NULL) { 1142 while (supported_mechs[i]->name != NULL) {
1264 if (GSS_ERROR(gss_test_oid_set_member(&min_status, 1143 if (GSS_ERROR(gss_test_oid_set_member(&min_status,
1265@@ -276,8 +305,48 @@ OM_uint32 1144@@ -276,8 +303,48 @@ OM_uint32
1266 ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client) 1145 ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client)
1267 { 1146 {
1268 int i = 0; 1147 int i = 0;
@@ -1278,21 +1157,21 @@ index ab3a15f0f..6c087a1b1 100644
1278+ return GSS_S_COMPLETE; 1157+ return GSS_S_COMPLETE;
1279+ } 1158+ }
1280+ 1159+
1281+ if ((ctx->major = gss_inquire_cred_by_mech(&ctx->minor, 1160+ if ((ctx->major = gss_inquire_cred_by_mech(&ctx->minor,
1282+ ctx->client_creds, ctx->oid, &new_name, 1161+ ctx->client_creds, ctx->oid, &new_name,
1283+ NULL, NULL, NULL))) { 1162+ NULL, NULL, NULL))) {
1284+ ssh_gssapi_error(ctx); 1163+ ssh_gssapi_error(ctx);
1285+ return (ctx->major); 1164+ return (ctx->major);
1286+ } 1165+ }
1287+ 1166+
1288+ ctx->major = gss_compare_name(&ctx->minor, client->name, 1167+ ctx->major = gss_compare_name(&ctx->minor, client->name,
1289+ new_name, &equal); 1168+ new_name, &equal);
1290+ 1169+
1291+ if (GSS_ERROR(ctx->major)) { 1170+ if (GSS_ERROR(ctx->major)) {
1292+ ssh_gssapi_error(ctx); 1171+ ssh_gssapi_error(ctx);
1293+ return (ctx->major); 1172+ return (ctx->major);
1294+ } 1173+ }
1295+ 1174+
1296+ if (!equal) { 1175+ if (!equal) {
1297+ debug("Rekeyed credentials have different name"); 1176+ debug("Rekeyed credentials have different name");
1298+ return GSS_S_COMPLETE; 1177+ return GSS_S_COMPLETE;
@@ -1305,14 +1184,14 @@ index ab3a15f0f..6c087a1b1 100644
1305+ gss_release_cred(&ctx->minor, &client->creds); 1184+ gss_release_cred(&ctx->minor, &client->creds);
1306+ client->name = new_name; 1185+ client->name = new_name;
1307+ client->creds = ctx->client_creds; 1186+ client->creds = ctx->client_creds;
1308+ ctx->client_creds = GSS_C_NO_CREDENTIAL; 1187+ ctx->client_creds = GSS_C_NO_CREDENTIAL;
1309+ client->updated = 1; 1188+ client->updated = 1;
1310+ return GSS_S_COMPLETE; 1189+ return GSS_S_COMPLETE;
1311+ } 1190+ }
1312 1191
1313 client->mech = NULL; 1192 client->mech = NULL;
1314 1193
1315@@ -292,6 +361,13 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client) 1194@@ -292,6 +359,13 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client)
1316 if (client->mech == NULL) 1195 if (client->mech == NULL)
1317 return GSS_S_FAILURE; 1196 return GSS_S_FAILURE;
1318 1197
@@ -1326,7 +1205,7 @@ index ab3a15f0f..6c087a1b1 100644
1326 if ((ctx->major = gss_display_name(&ctx->minor, ctx->client, 1205 if ((ctx->major = gss_display_name(&ctx->minor, ctx->client,
1327 &client->displayname, NULL))) { 1206 &client->displayname, NULL))) {
1328 ssh_gssapi_error(ctx); 1207 ssh_gssapi_error(ctx);
1329@@ -309,6 +385,8 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client) 1208@@ -309,6 +383,8 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client)
1330 return (ctx->major); 1209 return (ctx->major);
1331 } 1210 }
1332 1211
@@ -1335,16 +1214,20 @@ index ab3a15f0f..6c087a1b1 100644
1335 /* We can't copy this structure, so we just move the pointer to it */ 1214 /* We can't copy this structure, so we just move the pointer to it */
1336 client->creds = ctx->client_creds; 1215 client->creds = ctx->client_creds;
1337 ctx->client_creds = GSS_C_NO_CREDENTIAL; 1216 ctx->client_creds = GSS_C_NO_CREDENTIAL;
1338@@ -356,7 +434,7 @@ ssh_gssapi_do_child(char ***envp, u_int *envsizep) 1217@@ -356,19 +432,23 @@ ssh_gssapi_do_child(char ***envp, u_int *envsizep)
1339 1218
1340 /* Privileged */ 1219 /* Privileged */
1341 int 1220 int
1342-ssh_gssapi_userok(char *user) 1221-ssh_gssapi_userok(char *user)
1343+ssh_gssapi_userok(char *user, struct passwd *pw) 1222+ssh_gssapi_userok(char *user, struct passwd *pw, int kex)
1344 { 1223 {
1345 OM_uint32 lmin; 1224 OM_uint32 lmin;
1346 1225
1347@@ -366,9 +444,11 @@ ssh_gssapi_userok(char *user) 1226+ (void) kex; /* used in privilege separation */
1227+
1228 if (gssapi_client.exportedname.length == 0 ||
1229 gssapi_client.exportedname.value == NULL) {
1230 debug("No suitable client data");
1348 return 0; 1231 return 0;
1349 } 1232 }
1350 if (gssapi_client.mech && gssapi_client.mech->userok) 1233 if (gssapi_client.mech && gssapi_client.mech->userok)
@@ -1365,7 +1248,7 @@ index ab3a15f0f..6c087a1b1 100644
1365-/* Privileged */ 1248-/* Privileged */
1366-OM_uint32 1249-OM_uint32
1367-ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic) 1250-ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic)
1368+/* These bits are only used for rekeying. The unpriviledged child is running 1251+/* These bits are only used for rekeying. The unpriviledged child is running
1369+ * as the user, the monitor is root. 1252+ * as the user, the monitor is root.
1370+ * 1253+ *
1371+ * In the child, we want to : 1254+ * In the child, we want to :
@@ -1376,7 +1259,7 @@ index ab3a15f0f..6c087a1b1 100644
1376+/* Stuff for PAM */ 1259+/* Stuff for PAM */
1377+ 1260+
1378+#ifdef USE_PAM 1261+#ifdef USE_PAM
1379+static int ssh_gssapi_simple_conv(int n, const struct pam_message **msg, 1262+static int ssh_gssapi_simple_conv(int n, const struct pam_message **msg,
1380+ struct pam_response **resp, void *data) 1263+ struct pam_response **resp, void *data)
1381 { 1264 {
1382- ctx->major = gss_verify_mic(&ctx->minor, ctx->context, 1265- ctx->major = gss_verify_mic(&ctx->minor, ctx->context,
@@ -1389,18 +1272,18 @@ index ab3a15f0f..6c087a1b1 100644
1389+void 1272+void
1390+ssh_gssapi_rekey_creds(void) { 1273+ssh_gssapi_rekey_creds(void) {
1391+ int ok; 1274+ int ok;
1392+ int ret;
1393+#ifdef USE_PAM 1275+#ifdef USE_PAM
1276+ int ret;
1394+ pam_handle_t *pamh = NULL; 1277+ pam_handle_t *pamh = NULL;
1395+ struct pam_conv pamconv = {ssh_gssapi_simple_conv, NULL}; 1278+ struct pam_conv pamconv = {ssh_gssapi_simple_conv, NULL};
1396+ char *envstr; 1279+ char *envstr;
1397+#endif 1280+#endif
1398+ 1281+
1399+ if (gssapi_client.store.filename == NULL && 1282+ if (gssapi_client.store.filename == NULL &&
1400+ gssapi_client.store.envval == NULL && 1283+ gssapi_client.store.envval == NULL &&
1401+ gssapi_client.store.envvar == NULL) 1284+ gssapi_client.store.envvar == NULL)
1402+ return; 1285+ return;
1403+ 1286+
1404+ ok = PRIVSEP(ssh_gssapi_update_creds(&gssapi_client.store)); 1287+ ok = PRIVSEP(ssh_gssapi_update_creds(&gssapi_client.store));
1405+ 1288+
1406+ if (!ok) 1289+ if (!ok)
@@ -1423,7 +1306,7 @@ index ab3a15f0f..6c087a1b1 100644
1423+ if (ret) 1306+ if (ret)
1424+ return; 1307+ return;
1425+ 1308+
1426+ xasprintf(&envstr, "%s=%s", gssapi_client.store.envvar, 1309+ xasprintf(&envstr, "%s=%s", gssapi_client.store.envvar,
1427+ gssapi_client.store.envval); 1310+ gssapi_client.store.envval);
1428+ 1311+
1429+ ret = pam_putenv(pamh, envstr); 1312+ ret = pam_putenv(pamh, envstr);
@@ -1433,7 +1316,7 @@ index ab3a15f0f..6c087a1b1 100644
1433+#endif 1316+#endif
1434+} 1317+}
1435+ 1318+
1436+int 1319+int
1437+ssh_gssapi_update_creds(ssh_gssapi_ccache *store) { 1320+ssh_gssapi_update_creds(ssh_gssapi_ccache *store) {
1438+ int ok = 0; 1321+ int ok = 0;
1439+ 1322+
@@ -1455,11 +1338,29 @@ index ab3a15f0f..6c087a1b1 100644
1455 } 1338 }
1456 1339
1457 /* Privileged */ 1340 /* Privileged */
1341diff --git a/hmac.c b/hmac.c
1342index 1c879640c..a29f32c5c 100644
1343--- a/hmac.c
1344+++ b/hmac.c
1345@@ -19,6 +19,7 @@
1346
1347 #include <sys/types.h>
1348 #include <string.h>
1349+#include <stdlib.h>
1350
1351 #include "sshbuf.h"
1352 #include "digest.h"
1458diff --git a/kex.c b/kex.c 1353diff --git a/kex.c b/kex.c
1459index 25f9f66f6..fb5bfaea5 100644 1354index 34808b5c3..a2a4794e8 100644
1460--- a/kex.c 1355--- a/kex.c
1461+++ b/kex.c 1356+++ b/kex.c
1462@@ -54,6 +54,10 @@ 1357@@ -55,11 +55,16 @@
1358 #include "misc.h"
1359 #include "dispatch.h"
1360 #include "monitor.h"
1361+#include "xmalloc.h"
1362
1363 #include "ssherr.h"
1463 #include "sshbuf.h" 1364 #include "sshbuf.h"
1464 #include "digest.h" 1365 #include "digest.h"
1465 1366
@@ -1470,57 +1371,129 @@ index 25f9f66f6..fb5bfaea5 100644
1470 /* prototype */ 1371 /* prototype */
1471 static int kex_choose_conf(struct ssh *); 1372 static int kex_choose_conf(struct ssh *);
1472 static int kex_input_newkeys(int, u_int32_t, struct ssh *); 1373 static int kex_input_newkeys(int, u_int32_t, struct ssh *);
1473@@ -105,6 +109,14 @@ static const struct kexalg kexalgs[] = { 1374@@ -113,15 +118,28 @@ static const struct kexalg kexalgs[] = {
1474 #endif /* HAVE_EVP_SHA256 || !WITH_OPENSSL */ 1375 #endif /* HAVE_EVP_SHA256 || !WITH_OPENSSL */
1475 { NULL, -1, -1, -1}, 1376 { NULL, -1, -1, -1},
1476 }; 1377 };
1477+static const struct kexalg kexalg_prefixes[] = { 1378+static const struct kexalg gss_kexalgs[] = {
1478+#ifdef GSSAPI 1379+#ifdef GSSAPI
1479+ { KEX_GSS_GEX_SHA1_ID, KEX_GSS_GEX_SHA1, 0, SSH_DIGEST_SHA1 }, 1380+ { KEX_GSS_GEX_SHA1_ID, KEX_GSS_GEX_SHA1, 0, SSH_DIGEST_SHA1 },
1480+ { KEX_GSS_GRP1_SHA1_ID, KEX_GSS_GRP1_SHA1, 0, SSH_DIGEST_SHA1 }, 1381+ { KEX_GSS_GRP1_SHA1_ID, KEX_GSS_GRP1_SHA1, 0, SSH_DIGEST_SHA1 },
1481+ { KEX_GSS_GRP14_SHA1_ID, KEX_GSS_GRP14_SHA1, 0, SSH_DIGEST_SHA1 }, 1382+ { KEX_GSS_GRP14_SHA1_ID, KEX_GSS_GRP14_SHA1, 0, SSH_DIGEST_SHA1 },
1383+ { KEX_GSS_GRP14_SHA256_ID, KEX_GSS_GRP14_SHA256, 0, SSH_DIGEST_SHA256 },
1384+ { KEX_GSS_GRP16_SHA512_ID, KEX_GSS_GRP16_SHA512, 0, SSH_DIGEST_SHA512 },
1385+ { KEX_GSS_NISTP256_SHA256_ID, KEX_GSS_NISTP256_SHA256,
1386+ NID_X9_62_prime256v1, SSH_DIGEST_SHA256 },
1387+ { KEX_GSS_C25519_SHA256_ID, KEX_GSS_C25519_SHA256, 0, SSH_DIGEST_SHA256 },
1482+#endif 1388+#endif
1483+ { NULL, -1, -1, -1 }, 1389+ { NULL, -1, -1, -1 },
1484+}; 1390+};
1485 1391
1486 char * 1392-char *
1487 kex_alg_list(char sep) 1393-kex_alg_list(char sep)
1488@@ -137,6 +149,10 @@ kex_alg_by_name(const char *name) 1394+static char *
1395+kex_alg_list_internal(char sep, const struct kexalg *algs)
1396 {
1397 char *ret = NULL, *tmp;
1398 size_t nlen, rlen = 0;
1399 const struct kexalg *k;
1400
1401- for (k = kexalgs; k->name != NULL; k++) {
1402+ for (k = algs; k->name != NULL; k++) {
1403 if (ret != NULL)
1404 ret[rlen++] = sep;
1405 nlen = strlen(k->name);
1406@@ -136,6 +154,18 @@ kex_alg_list(char sep)
1407 return ret;
1408 }
1409
1410+char *
1411+kex_alg_list(char sep)
1412+{
1413+ return kex_alg_list_internal(sep, kexalgs);
1414+}
1415+
1416+char *
1417+kex_gss_alg_list(char sep)
1418+{
1419+ return kex_alg_list_internal(sep, gss_kexalgs);
1420+}
1421+
1422 static const struct kexalg *
1423 kex_alg_by_name(const char *name)
1424 {
1425@@ -145,6 +175,10 @@ kex_alg_by_name(const char *name)
1489 if (strcmp(k->name, name) == 0) 1426 if (strcmp(k->name, name) == 0)
1490 return k; 1427 return k;
1491 } 1428 }
1492+ for (k = kexalg_prefixes; k->name != NULL; k++) { 1429+ for (k = gss_kexalgs; k->name != NULL; k++) {
1493+ if (strncmp(k->name, name, strlen(k->name)) == 0) 1430+ if (strncmp(k->name, name, strlen(k->name)) == 0)
1494+ return k; 1431+ return k;
1495+ } 1432+ }
1496 return NULL; 1433 return NULL;
1497 } 1434 }
1498 1435
1499@@ -653,6 +669,9 @@ kex_free(struct kex *kex) 1436@@ -301,6 +335,29 @@ kex_assemble_names(char **listp, const char *def, const char *all)
1500 sshbuf_free(kex->peer); 1437 return r;
1501 sshbuf_free(kex->my); 1438 }
1439
1440+/* Validate GSS KEX method name list */
1441+int
1442+kex_gss_names_valid(const char *names)
1443+{
1444+ char *s, *cp, *p;
1445+
1446+ if (names == NULL || *names == '\0')
1447+ return 0;
1448+ s = cp = xstrdup(names);
1449+ for ((p = strsep(&cp, ",")); p && *p != '\0';
1450+ (p = strsep(&cp, ","))) {
1451+ if (strncmp(p, "gss-", 4) != 0
1452+ || kex_alg_by_name(p) == NULL) {
1453+ error("Unsupported KEX algorithm \"%.100s\"", p);
1454+ free(s);
1455+ return 0;
1456+ }
1457+ }
1458+ debug3("gss kex names ok: [%s]", names);
1459+ free(s);
1460+ return 1;
1461+}
1462+
1463 /* put algorithm proposal into buffer */
1464 int
1465 kex_prop2buf(struct sshbuf *b, char *proposal[PROPOSAL_MAX])
1466@@ -657,6 +714,9 @@ kex_free(struct kex *kex)
1467 sshbuf_free(kex->server_version);
1468 sshbuf_free(kex->client_pub);
1502 free(kex->session_id); 1469 free(kex->session_id);
1503+#ifdef GSSAPI 1470+#ifdef GSSAPI
1504+ free(kex->gss_host); 1471+ free(kex->gss_host);
1505+#endif /* GSSAPI */ 1472+#endif /* GSSAPI */
1506 free(kex->client_version_string);
1507 free(kex->server_version_string);
1508 free(kex->failed_choice); 1473 free(kex->failed_choice);
1474 free(kex->hostkey_alg);
1475 free(kex->name);
1509diff --git a/kex.h b/kex.h 1476diff --git a/kex.h b/kex.h
1510index 593de1208..4e5ead839 100644 1477index 6d446d1cc..2d5f1d4ed 100644
1511--- a/kex.h 1478--- a/kex.h
1512+++ b/kex.h 1479+++ b/kex.h
1513@@ -100,6 +100,9 @@ enum kex_exchange { 1480@@ -103,6 +103,15 @@ enum kex_exchange {
1514 KEX_DH_GEX_SHA256,
1515 KEX_ECDH_SHA2, 1481 KEX_ECDH_SHA2,
1516 KEX_C25519_SHA256, 1482 KEX_C25519_SHA256,
1483 KEX_KEM_SNTRUP4591761X25519_SHA512,
1484+#ifdef GSSAPI
1517+ KEX_GSS_GRP1_SHA1, 1485+ KEX_GSS_GRP1_SHA1,
1518+ KEX_GSS_GRP14_SHA1, 1486+ KEX_GSS_GRP14_SHA1,
1487+ KEX_GSS_GRP14_SHA256,
1488+ KEX_GSS_GRP16_SHA512,
1519+ KEX_GSS_GEX_SHA1, 1489+ KEX_GSS_GEX_SHA1,
1490+ KEX_GSS_NISTP256_SHA256,
1491+ KEX_GSS_C25519_SHA256,
1492+#endif
1520 KEX_MAX 1493 KEX_MAX
1521 }; 1494 };
1522 1495
1523@@ -148,6 +151,12 @@ struct kex { 1496@@ -154,6 +163,12 @@ struct kex {
1524 u_int flags; 1497 u_int flags;
1525 int hash_alg; 1498 int hash_alg;
1526 int ec_nid; 1499 int ec_nid;
@@ -1530,27 +1503,93 @@ index 593de1208..4e5ead839 100644
1530+ char *gss_host; 1503+ char *gss_host;
1531+ char *gss_client; 1504+ char *gss_client;
1532+#endif 1505+#endif
1533 char *client_version_string;
1534 char *server_version_string;
1535 char *failed_choice; 1506 char *failed_choice;
1536@@ -198,6 +207,11 @@ int kexecdh_server(struct ssh *); 1507 int (*verify_host_key)(struct sshkey *, struct ssh *);
1537 int kexc25519_client(struct ssh *); 1508 struct sshkey *(*load_host_public_key)(int, int, struct ssh *);
1538 int kexc25519_server(struct ssh *); 1509@@ -175,8 +190,10 @@ struct kex {
1539 1510
1540+#ifdef GSSAPI 1511 int kex_names_valid(const char *);
1512 char *kex_alg_list(char);
1513+char *kex_gss_alg_list(char);
1514 char *kex_names_cat(const char *, const char *);
1515 int kex_assemble_names(char **, const char *, const char *);
1516+int kex_gss_names_valid(const char *);
1517
1518 int kex_exchange_identification(struct ssh *, int, const char *);
1519
1520@@ -203,6 +220,12 @@ int kexgex_client(struct ssh *);
1521 int kexgex_server(struct ssh *);
1522 int kex_gen_client(struct ssh *);
1523 int kex_gen_server(struct ssh *);
1524+#if defined(GSSAPI) && defined(WITH_OPENSSL)
1525+int kexgssgex_client(struct ssh *);
1526+int kexgssgex_server(struct ssh *);
1541+int kexgss_client(struct ssh *); 1527+int kexgss_client(struct ssh *);
1542+int kexgss_server(struct ssh *); 1528+int kexgss_server(struct ssh *);
1543+#endif 1529+#endif
1544+ 1530
1545 int kex_dh_hash(int, const char *, const char *, 1531 int kex_dh_keypair(struct kex *);
1546 const u_char *, size_t, const u_char *, size_t, const u_char *, size_t, 1532 int kex_dh_enc(struct kex *, const struct sshbuf *, struct sshbuf **,
1547 const BIGNUM *, const BIGNUM *, const BIGNUM *, u_char *, size_t *); 1533@@ -235,6 +258,12 @@ int kexgex_hash(int, const struct sshbuf *, const struct sshbuf *,
1534 const BIGNUM *, const u_char *, size_t,
1535 u_char *, size_t *);
1536
1537+int kex_gen_hash(int hash_alg, const struct sshbuf *client_version,
1538+ const struct sshbuf *server_version, const struct sshbuf *client_kexinit,
1539+ const struct sshbuf *server_kexinit, const struct sshbuf *server_host_key_blob,
1540+ const struct sshbuf *client_pub, const struct sshbuf *server_pub,
1541+ const struct sshbuf *shared_secret, u_char *hash, size_t *hashlen);
1542+
1543 void kexc25519_keygen(u_char key[CURVE25519_SIZE], u_char pub[CURVE25519_SIZE])
1544 __attribute__((__bounded__(__minbytes__, 1, CURVE25519_SIZE)))
1545 __attribute__((__bounded__(__minbytes__, 2, CURVE25519_SIZE)));
1546diff --git a/kexdh.c b/kexdh.c
1547index 67133e339..edaa46762 100644
1548--- a/kexdh.c
1549+++ b/kexdh.c
1550@@ -48,13 +48,23 @@ kex_dh_keygen(struct kex *kex)
1551 {
1552 switch (kex->kex_type) {
1553 case KEX_DH_GRP1_SHA1:
1554+#ifdef GSSAPI
1555+ case KEX_GSS_GRP1_SHA1:
1556+#endif
1557 kex->dh = dh_new_group1();
1558 break;
1559 case KEX_DH_GRP14_SHA1:
1560 case KEX_DH_GRP14_SHA256:
1561+#ifdef GSSAPI
1562+ case KEX_GSS_GRP14_SHA1:
1563+ case KEX_GSS_GRP14_SHA256:
1564+#endif
1565 kex->dh = dh_new_group14();
1566 break;
1567 case KEX_DH_GRP16_SHA512:
1568+#ifdef GSSAPI
1569+ case KEX_GSS_GRP16_SHA512:
1570+#endif
1571 kex->dh = dh_new_group16();
1572 break;
1573 case KEX_DH_GRP18_SHA512:
1574diff --git a/kexgen.c b/kexgen.c
1575index 2abbb9ef6..569dc83f3 100644
1576--- a/kexgen.c
1577+++ b/kexgen.c
1578@@ -43,7 +43,7 @@
1579 static int input_kex_gen_init(int, u_int32_t, struct ssh *);
1580 static int input_kex_gen_reply(int type, u_int32_t seq, struct ssh *ssh);
1581
1582-static int
1583+int
1584 kex_gen_hash(
1585 int hash_alg,
1586 const struct sshbuf *client_version,
1548diff --git a/kexgssc.c b/kexgssc.c 1587diff --git a/kexgssc.c b/kexgssc.c
1549new file mode 100644 1588new file mode 100644
1550index 000000000..3c8ae08dd 1589index 000000000..f6e1405eb
1551--- /dev/null 1590--- /dev/null
1552+++ b/kexgssc.c 1591+++ b/kexgssc.c
1553@@ -0,0 +1,341 @@ 1592@@ -0,0 +1,606 @@
1554+/* 1593+/*
1555+ * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved. 1594+ * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved.
1556+ * 1595+ *
@@ -1577,7 +1616,7 @@ index 000000000..3c8ae08dd
1577+ 1616+
1578+#include "includes.h" 1617+#include "includes.h"
1579+ 1618+
1580+#ifdef GSSAPI 1619+#if defined(GSSAPI) && defined(WITH_OPENSSL)
1581+ 1620+
1582+#include "includes.h" 1621+#include "includes.h"
1583+ 1622+
@@ -1596,113 +1635,88 @@ index 000000000..3c8ae08dd
1596+#include "packet.h" 1635+#include "packet.h"
1597+#include "dh.h" 1636+#include "dh.h"
1598+#include "digest.h" 1637+#include "digest.h"
1638+#include "ssherr.h"
1599+ 1639+
1600+#include "ssh-gss.h" 1640+#include "ssh-gss.h"
1601+ 1641+
1602+int 1642+int
1603+kexgss_client(struct ssh *ssh) { 1643+kexgss_client(struct ssh *ssh)
1604+ gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; 1644+{
1605+ gss_buffer_desc recv_tok, gssbuf, msg_tok, *token_ptr; 1645+ struct kex *kex = ssh->kex;
1646+ gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER,
1647+ recv_tok = GSS_C_EMPTY_BUFFER,
1648+ gssbuf, msg_tok = GSS_C_EMPTY_BUFFER, *token_ptr;
1606+ Gssctxt *ctxt; 1649+ Gssctxt *ctxt;
1607+ OM_uint32 maj_status, min_status, ret_flags; 1650+ OM_uint32 maj_status, min_status, ret_flags;
1608+ u_int klen, kout, slen = 0, strlen; 1651+ struct sshbuf *server_blob = NULL;
1609+ DH *dh; 1652+ struct sshbuf *shared_secret = NULL;
1610+ BIGNUM *dh_server_pub = NULL; 1653+ struct sshbuf *server_host_key_blob = NULL;
1611+ BIGNUM *shared_secret = NULL; 1654+ struct sshbuf *empty = NULL;
1612+ const BIGNUM *pub_key, *dh_p, *dh_g; 1655+ u_char *msg;
1613+ BIGNUM *p = NULL;
1614+ BIGNUM *g = NULL;
1615+ u_char *kbuf;
1616+ u_char *serverhostkey = NULL;
1617+ u_char *empty = "";
1618+ char *msg;
1619+ int type = 0; 1656+ int type = 0;
1620+ int first = 1; 1657+ int first = 1;
1621+ int nbits = 0, min = DH_GRP_MIN, max = DH_GRP_MAX;
1622+ u_char hash[SSH_DIGEST_MAX_LENGTH]; 1658+ u_char hash[SSH_DIGEST_MAX_LENGTH];
1623+ size_t hashlen; 1659+ size_t hashlen;
1660+ u_char c;
1661+ int r;
1624+ 1662+
1625+ /* Initialise our GSSAPI world */ 1663+ /* Initialise our GSSAPI world */
1626+ ssh_gssapi_build_ctx(&ctxt); 1664+ ssh_gssapi_build_ctx(&ctxt);
1627+ if (ssh_gssapi_id_kex(ctxt, ssh->kex->name, ssh->kex->kex_type) 1665+ if (ssh_gssapi_id_kex(ctxt, kex->name, kex->kex_type)
1628+ == GSS_C_NO_OID) 1666+ == GSS_C_NO_OID)
1629+ fatal("Couldn't identify host exchange"); 1667+ fatal("Couldn't identify host exchange");
1630+ 1668+
1631+ if (ssh_gssapi_import_name(ctxt, ssh->kex->gss_host)) 1669+ if (ssh_gssapi_import_name(ctxt, kex->gss_host))
1632+ fatal("Couldn't import hostname"); 1670+ fatal("Couldn't import hostname");
1633+ 1671+
1634+ if (ssh->kex->gss_client && 1672+ if (kex->gss_client &&
1635+ ssh_gssapi_client_identity(ctxt, ssh->kex->gss_client)) 1673+ ssh_gssapi_client_identity(ctxt, kex->gss_client))
1636+ fatal("Couldn't acquire client credentials"); 1674+ fatal("Couldn't acquire client credentials");
1637+ 1675+
1638+ switch (ssh->kex->kex_type) { 1676+ /* Step 1 */
1677+ switch (kex->kex_type) {
1639+ case KEX_GSS_GRP1_SHA1: 1678+ case KEX_GSS_GRP1_SHA1:
1640+ dh = dh_new_group1();
1641+ break;
1642+ case KEX_GSS_GRP14_SHA1: 1679+ case KEX_GSS_GRP14_SHA1:
1643+ dh = dh_new_group14(); 1680+ case KEX_GSS_GRP14_SHA256:
1681+ case KEX_GSS_GRP16_SHA512:
1682+ r = kex_dh_keypair(kex);
1683+ break;
1684+ case KEX_GSS_NISTP256_SHA256:
1685+ r = kex_ecdh_keypair(kex);
1644+ break; 1686+ break;
1645+ case KEX_GSS_GEX_SHA1: 1687+ case KEX_GSS_C25519_SHA256:
1646+ debug("Doing group exchange\n"); 1688+ r = kex_c25519_keypair(kex);
1647+ nbits = dh_estimate(ssh->kex->we_need * 8);
1648+ packet_start(SSH2_MSG_KEXGSS_GROUPREQ);
1649+ packet_put_int(min);
1650+ packet_put_int(nbits);
1651+ packet_put_int(max);
1652+
1653+ packet_send();
1654+
1655+ packet_read_expect(SSH2_MSG_KEXGSS_GROUP);
1656+
1657+ if ((p = BN_new()) == NULL)
1658+ fatal("BN_new() failed");
1659+ packet_get_bignum2(p);
1660+ if ((g = BN_new()) == NULL)
1661+ fatal("BN_new() failed");
1662+ packet_get_bignum2(g);
1663+ packet_check_eom();
1664+
1665+ if (BN_num_bits(p) < min || BN_num_bits(p) > max)
1666+ fatal("GSSGRP_GEX group out of range: %d !< %d !< %d",
1667+ min, BN_num_bits(p), max);
1668+
1669+ dh = dh_new_group(g, p);
1670+ break; 1689+ break;
1671+ default: 1690+ default:
1672+ fatal("%s: Unexpected KEX type %d", __func__, ssh->kex->kex_type); 1691+ fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type);
1673+ } 1692+ }
1674+ 1693+ if (r != 0)
1675+ /* Step 1 - e is dh->pub_key */ 1694+ return r;
1676+ dh_gen_key(dh, ssh->kex->we_need * 8);
1677+ DH_get0_key(dh, &pub_key, NULL);
1678+ DH_get0_pqg(dh, &dh_p, NULL, &dh_g);
1679+
1680+ /* This is f, we initialise it now to make life easier */
1681+ dh_server_pub = BN_new();
1682+ if (dh_server_pub == NULL)
1683+ fatal("dh_server_pub == NULL");
1684+ 1695+
1685+ token_ptr = GSS_C_NO_BUFFER; 1696+ token_ptr = GSS_C_NO_BUFFER;
1686+ 1697+
1687+ do { 1698+ do {
1688+ debug("Calling gss_init_sec_context"); 1699+ debug("Calling gss_init_sec_context");
1689+ 1700+
1690+ maj_status = ssh_gssapi_init_ctx(ctxt, 1701+ maj_status = ssh_gssapi_init_ctx(ctxt,
1691+ ssh->kex->gss_deleg_creds, token_ptr, &send_tok, 1702+ kex->gss_deleg_creds, token_ptr, &send_tok,
1692+ &ret_flags); 1703+ &ret_flags);
1693+ 1704+
1694+ if (GSS_ERROR(maj_status)) { 1705+ if (GSS_ERROR(maj_status)) {
1706+ /* XXX Useles code: Missing send? */
1695+ if (send_tok.length != 0) { 1707+ if (send_tok.length != 0) {
1696+ packet_start(SSH2_MSG_KEXGSS_CONTINUE); 1708+ if ((r = sshpkt_start(ssh,
1697+ packet_put_string(send_tok.value, 1709+ SSH2_MSG_KEXGSS_CONTINUE)) != 0 ||
1698+ send_tok.length); 1710+ (r = sshpkt_put_string(ssh, send_tok.value,
1711+ send_tok.length)) != 0)
1712+ fatal("sshpkt failed: %s", ssh_err(r));
1699+ } 1713+ }
1700+ fatal("gss_init_context failed"); 1714+ fatal("gss_init_context failed");
1701+ } 1715+ }
1702+ 1716+
1703+ /* If we've got an old receive buffer get rid of it */ 1717+ /* If we've got an old receive buffer get rid of it */
1704+ if (token_ptr != GSS_C_NO_BUFFER) 1718+ if (token_ptr != GSS_C_NO_BUFFER)
1705+ free(recv_tok.value); 1719+ gss_release_buffer(&min_status, &recv_tok);
1706+ 1720+
1707+ if (maj_status == GSS_S_COMPLETE) { 1721+ if (maj_status == GSS_S_COMPLETE) {
1708+ /* If mutual state flag is not true, kex fails */ 1722+ /* If mutual state flag is not true, kex fails */
@@ -1714,75 +1728,90 @@ index 000000000..3c8ae08dd
1714+ fatal("Integrity check failed"); 1728+ fatal("Integrity check failed");
1715+ } 1729+ }
1716+ 1730+
1717+ /* 1731+ /*
1718+ * If we have data to send, then the last message that we 1732+ * If we have data to send, then the last message that we
1719+ * received cannot have been a 'complete'. 1733+ * received cannot have been a 'complete'.
1720+ */ 1734+ */
1721+ if (send_tok.length != 0) { 1735+ if (send_tok.length != 0) {
1722+ if (first) { 1736+ if (first) {
1723+ packet_start(SSH2_MSG_KEXGSS_INIT); 1737+ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_INIT)) != 0 ||
1724+ packet_put_string(send_tok.value, 1738+ (r = sshpkt_put_string(ssh, send_tok.value,
1725+ send_tok.length); 1739+ send_tok.length)) != 0 ||
1726+ packet_put_bignum2(pub_key); 1740+ (r = sshpkt_put_stringb(ssh, kex->client_pub)) != 0)
1741+ fatal("failed to construct packet: %s", ssh_err(r));
1727+ first = 0; 1742+ first = 0;
1728+ } else { 1743+ } else {
1729+ packet_start(SSH2_MSG_KEXGSS_CONTINUE); 1744+ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_CONTINUE)) != 0 ||
1730+ packet_put_string(send_tok.value, 1745+ (r = sshpkt_put_string(ssh, send_tok.value,
1731+ send_tok.length); 1746+ send_tok.length)) != 0)
1747+ fatal("failed to construct packet: %s", ssh_err(r));
1732+ } 1748+ }
1733+ packet_send(); 1749+ if ((r = sshpkt_send(ssh)) != 0)
1750+ fatal("failed to send packet: %s", ssh_err(r));
1734+ gss_release_buffer(&min_status, &send_tok); 1751+ gss_release_buffer(&min_status, &send_tok);
1735+ 1752+
1736+ /* If we've sent them data, they should reply */ 1753+ /* If we've sent them data, they should reply */
1737+ do { 1754+ do {
1738+ type = packet_read(); 1755+ type = ssh_packet_read(ssh);
1739+ if (type == SSH2_MSG_KEXGSS_HOSTKEY) { 1756+ if (type == SSH2_MSG_KEXGSS_HOSTKEY) {
1740+ debug("Received KEXGSS_HOSTKEY"); 1757+ debug("Received KEXGSS_HOSTKEY");
1741+ if (serverhostkey) 1758+ if (server_host_key_blob)
1742+ fatal("Server host key received more than once"); 1759+ fatal("Server host key received more than once");
1743+ serverhostkey = 1760+ if ((r = sshpkt_getb_froms(ssh, &server_host_key_blob)) != 0)
1744+ packet_get_string(&slen); 1761+ fatal("Failed to read server host key: %s", ssh_err(r));
1745+ } 1762+ }
1746+ } while (type == SSH2_MSG_KEXGSS_HOSTKEY); 1763+ } while (type == SSH2_MSG_KEXGSS_HOSTKEY);
1747+ 1764+
1748+ switch (type) { 1765+ switch (type) {
1749+ case SSH2_MSG_KEXGSS_CONTINUE: 1766+ case SSH2_MSG_KEXGSS_CONTINUE:
1750+ debug("Received GSSAPI_CONTINUE"); 1767+ debug("Received GSSAPI_CONTINUE");
1751+ if (maj_status == GSS_S_COMPLETE) 1768+ if (maj_status == GSS_S_COMPLETE)
1752+ fatal("GSSAPI Continue received from server when complete"); 1769+ fatal("GSSAPI Continue received from server when complete");
1753+ recv_tok.value = packet_get_string(&strlen); 1770+ if ((r = ssh_gssapi_sshpkt_get_buffer_desc(ssh,
1754+ recv_tok.length = strlen; 1771+ &recv_tok)) != 0 ||
1772+ (r = sshpkt_get_end(ssh)) != 0)
1773+ fatal("Failed to read token: %s", ssh_err(r));
1755+ break; 1774+ break;
1756+ case SSH2_MSG_KEXGSS_COMPLETE: 1775+ case SSH2_MSG_KEXGSS_COMPLETE:
1757+ debug("Received GSSAPI_COMPLETE"); 1776+ debug("Received GSSAPI_COMPLETE");
1758+ packet_get_bignum2(dh_server_pub); 1777+ if (msg_tok.value != NULL)
1759+ msg_tok.value = packet_get_string(&strlen); 1778+ fatal("Received GSSAPI_COMPLETE twice?");
1760+ msg_tok.length = strlen; 1779+ if ((r = sshpkt_getb_froms(ssh, &server_blob)) != 0 ||
1780+ (r = ssh_gssapi_sshpkt_get_buffer_desc(ssh,
1781+ &msg_tok)) != 0)
1782+ fatal("Failed to read message: %s", ssh_err(r));
1761+ 1783+
1762+ /* Is there a token included? */ 1784+ /* Is there a token included? */
1763+ if (packet_get_char()) { 1785+ if ((r = sshpkt_get_u8(ssh, &c)) != 0)
1764+ recv_tok.value= 1786+ fatal("sshpkt failed: %s", ssh_err(r));
1765+ packet_get_string(&strlen); 1787+ if (c) {
1766+ recv_tok.length = strlen; 1788+ if ((r = ssh_gssapi_sshpkt_get_buffer_desc(
1789+ ssh, &recv_tok)) != 0)
1790+ fatal("Failed to read token: %s", ssh_err(r));
1767+ /* If we're already complete - protocol error */ 1791+ /* If we're already complete - protocol error */
1768+ if (maj_status == GSS_S_COMPLETE) 1792+ if (maj_status == GSS_S_COMPLETE)
1769+ packet_disconnect("Protocol error: received token when complete"); 1793+ sshpkt_disconnect(ssh, "Protocol error: received token when complete");
1770+ } else { 1794+ } else {
1771+ /* No token included */ 1795+ /* No token included */
1772+ if (maj_status != GSS_S_COMPLETE) 1796+ if (maj_status != GSS_S_COMPLETE)
1773+ packet_disconnect("Protocol error: did not receive final token"); 1797+ sshpkt_disconnect(ssh, "Protocol error: did not receive final token");
1798+ }
1799+ if ((r = sshpkt_get_end(ssh)) != 0) {
1800+ fatal("Expecting end of packet.");
1774+ } 1801+ }
1775+ break; 1802+ break;
1776+ case SSH2_MSG_KEXGSS_ERROR: 1803+ case SSH2_MSG_KEXGSS_ERROR:
1777+ debug("Received Error"); 1804+ debug("Received Error");
1778+ maj_status = packet_get_int(); 1805+ if ((r = sshpkt_get_u32(ssh, &maj_status)) != 0 ||
1779+ min_status = packet_get_int(); 1806+ (r = sshpkt_get_u32(ssh, &min_status)) != 0 ||
1780+ msg = packet_get_string(NULL); 1807+ (r = sshpkt_get_string(ssh, &msg, NULL)) != 0 ||
1781+ (void) packet_get_string_ptr(NULL); 1808+ (r = sshpkt_get_string(ssh, NULL, NULL)) != 0 || /* lang tag */
1782+ fatal("GSSAPI Error: \n%.400s",msg); 1809+ (r = sshpkt_get_end(ssh)) != 0)
1810+ fatal("sshpkt_get failed: %s", ssh_err(r));
1811+ fatal("GSSAPI Error: \n%.400s", msg);
1783+ default: 1812+ default:
1784+ packet_disconnect("Protocol error: didn't expect packet type %d", 1813+ sshpkt_disconnect(ssh, "Protocol error: didn't expect packet type %d",
1785+ type); 1814+ type);
1786+ } 1815+ }
1787+ token_ptr = &recv_tok; 1816+ token_ptr = &recv_tok;
1788+ } else { 1817+ } else {
@@ -1792,93 +1821,358 @@ index 000000000..3c8ae08dd
1792+ } 1821+ }
1793+ } while (maj_status & GSS_S_CONTINUE_NEEDED); 1822+ } while (maj_status & GSS_S_CONTINUE_NEEDED);
1794+ 1823+
1795+ /* 1824+ /*
1796+ * We _must_ have received a COMPLETE message in reply from the 1825+ * We _must_ have received a COMPLETE message in reply from the
1797+ * server, which will have set dh_server_pub and msg_tok 1826+ * server, which will have set server_blob and msg_tok
1798+ */ 1827+ */
1799+ 1828+
1800+ if (type != SSH2_MSG_KEXGSS_COMPLETE) 1829+ if (type != SSH2_MSG_KEXGSS_COMPLETE)
1801+ fatal("Didn't receive a SSH2_MSG_KEXGSS_COMPLETE when I expected it"); 1830+ fatal("Didn't receive a SSH2_MSG_KEXGSS_COMPLETE when I expected it");
1802+ 1831+
1803+ /* Check f in range [1, p-1] */ 1832+ /* compute shared secret */
1804+ if (!dh_pub_is_valid(dh, dh_server_pub)) 1833+ switch (kex->kex_type) {
1805+ packet_disconnect("bad server public DH value");
1806+
1807+ /* compute K=f^x mod p */
1808+ klen = DH_size(dh);
1809+ kbuf = xmalloc(klen);
1810+ kout = DH_compute_key(kbuf, dh_server_pub, dh);
1811+ if (kout < 0)
1812+ fatal("DH_compute_key: failed");
1813+
1814+ shared_secret = BN_new();
1815+ if (shared_secret == NULL)
1816+ fatal("kexgss_client: BN_new failed");
1817+
1818+ if (BN_bin2bn(kbuf, kout, shared_secret) == NULL)
1819+ fatal("kexdh_client: BN_bin2bn failed");
1820+
1821+ memset(kbuf, 0, klen);
1822+ free(kbuf);
1823+
1824+ hashlen = sizeof(hash);
1825+ switch (ssh->kex->kex_type) {
1826+ case KEX_GSS_GRP1_SHA1: 1834+ case KEX_GSS_GRP1_SHA1:
1827+ case KEX_GSS_GRP14_SHA1: 1835+ case KEX_GSS_GRP14_SHA1:
1828+ kex_dh_hash( 1836+ case KEX_GSS_GRP14_SHA256:
1829+ ssh->kex->hash_alg, 1837+ case KEX_GSS_GRP16_SHA512:
1830+ ssh->kex->client_version_string, 1838+ r = kex_dh_dec(kex, server_blob, &shared_secret);
1831+ ssh->kex->server_version_string, 1839+ break;
1832+ sshbuf_ptr(ssh->kex->my), sshbuf_len(ssh->kex->my), 1840+ case KEX_GSS_C25519_SHA256:
1833+ sshbuf_ptr(ssh->kex->peer), sshbuf_len(ssh->kex->peer), 1841+ if (sshbuf_ptr(server_blob)[sshbuf_len(server_blob)] & 0x80)
1834+ (serverhostkey ? serverhostkey : empty), slen, 1842+ fatal("The received key has MSB of last octet set!");
1835+ pub_key, /* e */ 1843+ r = kex_c25519_dec(kex, server_blob, &shared_secret);
1836+ dh_server_pub, /* f */
1837+ shared_secret, /* K */
1838+ hash, &hashlen
1839+ );
1840+ break; 1844+ break;
1841+ case KEX_GSS_GEX_SHA1: 1845+ case KEX_GSS_NISTP256_SHA256:
1842+ kexgex_hash( 1846+ if (sshbuf_len(server_blob) != 65)
1843+ ssh->kex->hash_alg, 1847+ fatal("The received NIST-P256 key did not match"
1844+ ssh->kex->client_version_string, 1848+ "expected length (expected 65, got %zu)", sshbuf_len(server_blob));
1845+ ssh->kex->server_version_string, 1849+
1846+ sshbuf_ptr(ssh->kex->my), sshbuf_len(ssh->kex->my), 1850+ if (sshbuf_ptr(server_blob)[0] != POINT_CONVERSION_UNCOMPRESSED)
1847+ sshbuf_ptr(ssh->kex->peer), sshbuf_len(ssh->kex->peer), 1851+ fatal("The received NIST-P256 key does not have first octet 0x04");
1848+ (serverhostkey ? serverhostkey : empty), slen, 1852+
1849+ min, nbits, max, 1853+ r = kex_ecdh_dec(kex, server_blob, &shared_secret);
1850+ dh_p, dh_g,
1851+ pub_key,
1852+ dh_server_pub,
1853+ shared_secret,
1854+ hash, &hashlen
1855+ );
1856+ break; 1854+ break;
1857+ default: 1855+ default:
1858+ fatal("%s: Unexpected KEX type %d", __func__, ssh->kex->kex_type); 1856+ r = SSH_ERR_INVALID_ARGUMENT;
1857+ break;
1858+ }
1859+ if (r != 0)
1860+ goto out;
1861+
1862+ if ((empty = sshbuf_new()) == NULL) {
1863+ r = SSH_ERR_ALLOC_FAIL;
1864+ goto out;
1859+ } 1865+ }
1860+ 1866+
1867+ hashlen = sizeof(hash);
1868+ if ((r = kex_gen_hash(
1869+ kex->hash_alg,
1870+ kex->client_version,
1871+ kex->server_version,
1872+ kex->my,
1873+ kex->peer,
1874+ (server_host_key_blob ? server_host_key_blob : empty),
1875+ kex->client_pub,
1876+ server_blob,
1877+ shared_secret,
1878+ hash, &hashlen)) != 0)
1879+ fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type);
1880+
1861+ gssbuf.value = hash; 1881+ gssbuf.value = hash;
1862+ gssbuf.length = hashlen; 1882+ gssbuf.length = hashlen;
1863+ 1883+
1864+ /* Verify that the hash matches the MIC we just got. */ 1884+ /* Verify that the hash matches the MIC we just got. */
1865+ if (GSS_ERROR(ssh_gssapi_checkmic(ctxt, &gssbuf, &msg_tok))) 1885+ if (GSS_ERROR(ssh_gssapi_checkmic(ctxt, &gssbuf, &msg_tok)))
1866+ packet_disconnect("Hash's MIC didn't verify"); 1886+ sshpkt_disconnect(ssh, "Hash's MIC didn't verify");
1867+ 1887+
1868+ free(msg_tok.value); 1888+ gss_release_buffer(&min_status, &msg_tok);
1869+ 1889+
1870+ DH_free(dh); 1890+ if (kex->gss_deleg_creds)
1871+ free(serverhostkey); 1891+ ssh_gssapi_credentials_updated(ctxt);
1872+ BN_clear_free(dh_server_pub); 1892+
1893+ if (gss_kex_context == NULL)
1894+ gss_kex_context = ctxt;
1895+ else
1896+ ssh_gssapi_delete_ctx(&ctxt);
1897+
1898+ if ((r = kex_derive_keys(ssh, hash, hashlen, shared_secret)) == 0)
1899+ r = kex_send_newkeys(ssh);
1900+
1901+out:
1902+ explicit_bzero(hash, sizeof(hash));
1903+ explicit_bzero(kex->c25519_client_key, sizeof(kex->c25519_client_key));
1904+ sshbuf_free(empty);
1905+ sshbuf_free(server_host_key_blob);
1906+ sshbuf_free(server_blob);
1907+ sshbuf_free(shared_secret);
1908+ sshbuf_free(kex->client_pub);
1909+ kex->client_pub = NULL;
1910+ return r;
1911+}
1912+
1913+int
1914+kexgssgex_client(struct ssh *ssh)
1915+{
1916+ struct kex *kex = ssh->kex;
1917+ gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER,
1918+ recv_tok = GSS_C_EMPTY_BUFFER, gssbuf,
1919+ msg_tok = GSS_C_EMPTY_BUFFER, *token_ptr;
1920+ Gssctxt *ctxt;
1921+ OM_uint32 maj_status, min_status, ret_flags;
1922+ struct sshbuf *shared_secret = NULL;
1923+ BIGNUM *p = NULL;
1924+ BIGNUM *g = NULL;
1925+ struct sshbuf *buf = NULL;
1926+ struct sshbuf *server_host_key_blob = NULL;
1927+ struct sshbuf *server_blob = NULL;
1928+ BIGNUM *dh_server_pub = NULL;
1929+ u_char *msg;
1930+ int type = 0;
1931+ int first = 1;
1932+ u_char hash[SSH_DIGEST_MAX_LENGTH];
1933+ size_t hashlen;
1934+ const BIGNUM *pub_key, *dh_p, *dh_g;
1935+ int nbits = 0, min = DH_GRP_MIN, max = DH_GRP_MAX;
1936+ struct sshbuf *empty = NULL;
1937+ u_char c;
1938+ int r;
1939+
1940+ /* Initialise our GSSAPI world */
1941+ ssh_gssapi_build_ctx(&ctxt);
1942+ if (ssh_gssapi_id_kex(ctxt, kex->name, kex->kex_type)
1943+ == GSS_C_NO_OID)
1944+ fatal("Couldn't identify host exchange");
1945+
1946+ if (ssh_gssapi_import_name(ctxt, kex->gss_host))
1947+ fatal("Couldn't import hostname");
1948+
1949+ if (kex->gss_client &&
1950+ ssh_gssapi_client_identity(ctxt, kex->gss_client))
1951+ fatal("Couldn't acquire client credentials");
1952+
1953+ debug("Doing group exchange");
1954+ nbits = dh_estimate(kex->dh_need * 8);
1955+
1956+ kex->min = DH_GRP_MIN;
1957+ kex->max = DH_GRP_MAX;
1958+ kex->nbits = nbits;
1959+ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_GROUPREQ)) != 0 ||
1960+ (r = sshpkt_put_u32(ssh, min)) != 0 ||
1961+ (r = sshpkt_put_u32(ssh, nbits)) != 0 ||
1962+ (r = sshpkt_put_u32(ssh, max)) != 0 ||
1963+ (r = sshpkt_send(ssh)) != 0)
1964+ fatal("Failed to construct a packet: %s", ssh_err(r));
1965+
1966+ if ((r = ssh_packet_read_expect(ssh, SSH2_MSG_KEXGSS_GROUP)) != 0)
1967+ fatal("Error: %s", ssh_err(r));
1968+
1969+ if ((r = sshpkt_get_bignum2(ssh, &p)) != 0 ||
1970+ (r = sshpkt_get_bignum2(ssh, &g)) != 0 ||
1971+ (r = sshpkt_get_end(ssh)) != 0)
1972+ fatal("shpkt_get_bignum2 failed: %s", ssh_err(r));
1973+
1974+ if (BN_num_bits(p) < min || BN_num_bits(p) > max)
1975+ fatal("GSSGRP_GEX group out of range: %d !< %d !< %d",
1976+ min, BN_num_bits(p), max);
1977+
1978+ if ((kex->dh = dh_new_group(g, p)) == NULL)
1979+ fatal("dn_new_group() failed");
1980+ p = g = NULL; /* belong to kex->dh now */
1981+
1982+ if ((r = dh_gen_key(kex->dh, kex->we_need * 8)) != 0)
1983+ goto out;
1984+ DH_get0_key(kex->dh, &pub_key, NULL);
1985+
1986+ token_ptr = GSS_C_NO_BUFFER;
1987+
1988+ do {
1989+ /* Step 2 - call GSS_Init_sec_context() */
1990+ debug("Calling gss_init_sec_context");
1991+
1992+ maj_status = ssh_gssapi_init_ctx(ctxt,
1993+ kex->gss_deleg_creds, token_ptr, &send_tok,
1994+ &ret_flags);
1995+
1996+ if (GSS_ERROR(maj_status)) {
1997+ /* XXX Useles code: Missing send? */
1998+ if (send_tok.length != 0) {
1999+ if ((r = sshpkt_start(ssh,
2000+ SSH2_MSG_KEXGSS_CONTINUE)) != 0 ||
2001+ (r = sshpkt_put_string(ssh, send_tok.value,
2002+ send_tok.length)) != 0)
2003+ fatal("sshpkt failed: %s", ssh_err(r));
2004+ }
2005+ fatal("gss_init_context failed");
2006+ }
2007+
2008+ /* If we've got an old receive buffer get rid of it */
2009+ if (token_ptr != GSS_C_NO_BUFFER)
2010+ gss_release_buffer(&min_status, &recv_tok);
2011+
2012+ if (maj_status == GSS_S_COMPLETE) {
2013+ /* If mutual state flag is not true, kex fails */
2014+ if (!(ret_flags & GSS_C_MUTUAL_FLAG))
2015+ fatal("Mutual authentication failed");
2016+
2017+ /* If integ avail flag is not true kex fails */
2018+ if (!(ret_flags & GSS_C_INTEG_FLAG))
2019+ fatal("Integrity check failed");
2020+ }
2021+
2022+ /*
2023+ * If we have data to send, then the last message that we
2024+ * received cannot have been a 'complete'.
2025+ */
2026+ if (send_tok.length != 0) {
2027+ if (first) {
2028+ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_INIT)) != 0 ||
2029+ (r = sshpkt_put_string(ssh, send_tok.value,
2030+ send_tok.length)) != 0 ||
2031+ (r = sshpkt_put_bignum2(ssh, pub_key)) != 0)
2032+ fatal("sshpkt failed: %s", ssh_err(r));
2033+ first = 0;
2034+ } else {
2035+ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_CONTINUE)) != 0 ||
2036+ (r = sshpkt_put_string(ssh,send_tok.value,
2037+ send_tok.length)) != 0)
2038+ fatal("sshpkt failed: %s", ssh_err(r));
2039+ }
2040+ if ((r = sshpkt_send(ssh)) != 0)
2041+ fatal("sshpkt_send failed: %s", ssh_err(r));
2042+ gss_release_buffer(&min_status, &send_tok);
2043+
2044+ /* If we've sent them data, they should reply */
2045+ do {
2046+ type = ssh_packet_read(ssh);
2047+ if (type == SSH2_MSG_KEXGSS_HOSTKEY) {
2048+ debug("Received KEXGSS_HOSTKEY");
2049+ if (server_host_key_blob)
2050+ fatal("Server host key received more than once");
2051+ if ((r = sshpkt_getb_froms(ssh, &server_host_key_blob)) != 0)
2052+ fatal("sshpkt failed: %s", ssh_err(r));
2053+ }
2054+ } while (type == SSH2_MSG_KEXGSS_HOSTKEY);
2055+
2056+ switch (type) {
2057+ case SSH2_MSG_KEXGSS_CONTINUE:
2058+ debug("Received GSSAPI_CONTINUE");
2059+ if (maj_status == GSS_S_COMPLETE)
2060+ fatal("GSSAPI Continue received from server when complete");
2061+ if ((r = ssh_gssapi_sshpkt_get_buffer_desc(ssh,
2062+ &recv_tok)) != 0 ||
2063+ (r = sshpkt_get_end(ssh)) != 0)
2064+ fatal("sshpkt failed: %s", ssh_err(r));
2065+ break;
2066+ case SSH2_MSG_KEXGSS_COMPLETE:
2067+ debug("Received GSSAPI_COMPLETE");
2068+ if (msg_tok.value != NULL)
2069+ fatal("Received GSSAPI_COMPLETE twice?");
2070+ if ((r = sshpkt_getb_froms(ssh, &server_blob)) != 0 ||
2071+ (r = ssh_gssapi_sshpkt_get_buffer_desc(ssh,
2072+ &msg_tok)) != 0)
2073+ fatal("sshpkt failed: %s", ssh_err(r));
2074+
2075+ /* Is there a token included? */
2076+ if ((r = sshpkt_get_u8(ssh, &c)) != 0)
2077+ fatal("sshpkt failed: %s", ssh_err(r));
2078+ if (c) {
2079+ if ((r = ssh_gssapi_sshpkt_get_buffer_desc(
2080+ ssh, &recv_tok)) != 0 ||
2081+ (r = sshpkt_get_end(ssh)) != 0)
2082+ fatal("sshpkt failed: %s", ssh_err(r));
2083+ /* If we're already complete - protocol error */
2084+ if (maj_status == GSS_S_COMPLETE)
2085+ sshpkt_disconnect(ssh, "Protocol error: received token when complete");
2086+ } else {
2087+ /* No token included */
2088+ if (maj_status != GSS_S_COMPLETE)
2089+ sshpkt_disconnect(ssh, "Protocol error: did not receive final token");
2090+ }
2091+ break;
2092+ case SSH2_MSG_KEXGSS_ERROR:
2093+ debug("Received Error");
2094+ if ((r = sshpkt_get_u32(ssh, &maj_status)) != 0 ||
2095+ (r = sshpkt_get_u32(ssh, &min_status)) != 0 ||
2096+ (r = sshpkt_get_string(ssh, &msg, NULL)) != 0 ||
2097+ (r = sshpkt_get_string(ssh, NULL, NULL)) != 0 || /* lang tag */
2098+ (r = sshpkt_get_end(ssh)) != 0)
2099+ fatal("sshpkt failed: %s", ssh_err(r));
2100+ fatal("GSSAPI Error: \n%.400s", msg);
2101+ default:
2102+ sshpkt_disconnect(ssh, "Protocol error: didn't expect packet type %d",
2103+ type);
2104+ }
2105+ token_ptr = &recv_tok;
2106+ } else {
2107+ /* No data, and not complete */
2108+ if (maj_status != GSS_S_COMPLETE)
2109+ fatal("Not complete, and no token output");
2110+ }
2111+ } while (maj_status & GSS_S_CONTINUE_NEEDED);
2112+
2113+ /*
2114+ * We _must_ have received a COMPLETE message in reply from the
2115+ * server, which will have set dh_server_pub and msg_tok
2116+ */
2117+
2118+ if (type != SSH2_MSG_KEXGSS_COMPLETE)
2119+ fatal("Didn't receive a SSH2_MSG_KEXGSS_COMPLETE when I expected it");
2120+
2121+ /* 7. C verifies that the key Q_S is valid */
2122+ /* 8. C computes shared secret */
2123+ if ((buf = sshbuf_new()) == NULL ||
2124+ (r = sshbuf_put_stringb(buf, server_blob)) != 0 ||
2125+ (r = sshbuf_get_bignum2(buf, &dh_server_pub)) != 0)
2126+ goto out;
2127+ sshbuf_free(buf);
2128+ buf = NULL;
2129+
2130+ if ((shared_secret = sshbuf_new()) == NULL) {
2131+ r = SSH_ERR_ALLOC_FAIL;
2132+ goto out;
2133+ }
2134+
2135+ if ((r = kex_dh_compute_key(kex, dh_server_pub, shared_secret)) != 0)
2136+ goto out;
2137+ if ((empty = sshbuf_new()) == NULL) {
2138+ r = SSH_ERR_ALLOC_FAIL;
2139+ goto out;
2140+ }
2141+
2142+ DH_get0_pqg(kex->dh, &dh_p, NULL, &dh_g);
2143+ hashlen = sizeof(hash);
2144+ if ((r = kexgex_hash(
2145+ kex->hash_alg,
2146+ kex->client_version,
2147+ kex->server_version,
2148+ kex->my,
2149+ kex->peer,
2150+ (server_host_key_blob ? server_host_key_blob : empty),
2151+ kex->min, kex->nbits, kex->max,
2152+ dh_p, dh_g,
2153+ pub_key,
2154+ dh_server_pub,
2155+ sshbuf_ptr(shared_secret), sshbuf_len(shared_secret),
2156+ hash, &hashlen)) != 0)
2157+ fatal("Failed to calculate hash: %s", ssh_err(r));
2158+
2159+ gssbuf.value = hash;
2160+ gssbuf.length = hashlen;
2161+
2162+ /* Verify that the hash matches the MIC we just got. */
2163+ if (GSS_ERROR(ssh_gssapi_checkmic(ctxt, &gssbuf, &msg_tok)))
2164+ sshpkt_disconnect(ssh, "Hash's MIC didn't verify");
2165+
2166+ gss_release_buffer(&min_status, &msg_tok);
1873+ 2167+
1874+ /* save session id */ 2168+ /* save session id */
1875+ if (ssh->kex->session_id == NULL) { 2169+ if (kex->session_id == NULL) {
1876+ ssh->kex->session_id_len = hashlen; 2170+ kex->session_id_len = hashlen;
1877+ ssh->kex->session_id = xmalloc(ssh->kex->session_id_len); 2171+ kex->session_id = xmalloc(kex->session_id_len);
1878+ memcpy(ssh->kex->session_id, hash, ssh->kex->session_id_len); 2172+ memcpy(kex->session_id, hash, kex->session_id_len);
1879+ } 2173+ }
1880+ 2174+
1881+ if (ssh->kex->gss_deleg_creds) 2175+ if (kex->gss_deleg_creds)
1882+ ssh_gssapi_credentials_updated(ctxt); 2176+ ssh_gssapi_credentials_updated(ctxt);
1883+ 2177+
1884+ if (gss_kex_context == NULL) 2178+ if (gss_kex_context == NULL)
@@ -1886,18 +2180,28 @@ index 000000000..3c8ae08dd
1886+ else 2180+ else
1887+ ssh_gssapi_delete_ctx(&ctxt); 2181+ ssh_gssapi_delete_ctx(&ctxt);
1888+ 2182+
1889+ kex_derive_keys_bn(ssh, hash, hashlen, shared_secret); 2183+ /* Finally derive the keys and send them */
1890+ BN_clear_free(shared_secret); 2184+ if ((r = kex_derive_keys(ssh, hash, hashlen, shared_secret)) == 0)
1891+ return kex_send_newkeys(ssh); 2185+ r = kex_send_newkeys(ssh);
2186+out:
2187+ sshbuf_free(buf);
2188+ sshbuf_free(server_blob);
2189+ sshbuf_free(empty);
2190+ explicit_bzero(hash, sizeof(hash));
2191+ DH_free(kex->dh);
2192+ kex->dh = NULL;
2193+ BN_clear_free(dh_server_pub);
2194+ sshbuf_free(shared_secret);
2195+ sshbuf_free(server_host_key_blob);
2196+ return r;
1892+} 2197+}
1893+ 2198+#endif /* defined(GSSAPI) && defined(WITH_OPENSSL) */
1894+#endif /* GSSAPI */
1895diff --git a/kexgsss.c b/kexgsss.c 2199diff --git a/kexgsss.c b/kexgsss.c
1896new file mode 100644 2200new file mode 100644
1897index 000000000..18070f1d7 2201index 000000000..60bc02deb
1898--- /dev/null 2202--- /dev/null
1899+++ b/kexgsss.c 2203+++ b/kexgsss.c
1900@@ -0,0 +1,300 @@ 2204@@ -0,0 +1,474 @@
1901+/* 2205+/*
1902+ * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved. 2206+ * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved.
1903+ * 2207+ *
@@ -1924,7 +2228,7 @@ index 000000000..18070f1d7
1924+ 2228+
1925+#include "includes.h" 2229+#include "includes.h"
1926+ 2230+
1927+#ifdef GSSAPI 2231+#if defined(GSSAPI) && defined(WITH_OPENSSL)
1928+ 2232+
1929+#include <string.h> 2233+#include <string.h>
1930+ 2234+
@@ -1942,40 +2246,41 @@ index 000000000..18070f1d7
1942+#include "dh.h" 2246+#include "dh.h"
1943+#include "ssh-gss.h" 2247+#include "ssh-gss.h"
1944+#include "monitor_wrap.h" 2248+#include "monitor_wrap.h"
1945+#include "misc.h" 2249+#include "misc.h" /* servconf.h needs misc.h for struct ForwardOptions */
1946+#include "servconf.h" 2250+#include "servconf.h"
2251+#include "ssh-gss.h"
1947+#include "digest.h" 2252+#include "digest.h"
2253+#include "ssherr.h"
1948+ 2254+
1949+extern ServerOptions options; 2255+extern ServerOptions options;
1950+ 2256+
1951+int 2257+int
1952+kexgss_server(struct ssh *ssh) 2258+kexgss_server(struct ssh *ssh)
1953+{ 2259+{
2260+ struct kex *kex = ssh->kex;
1954+ OM_uint32 maj_status, min_status; 2261+ OM_uint32 maj_status, min_status;
1955+ 2262+
1956+ /* 2263+ /*
1957+ * Some GSSAPI implementations use the input value of ret_flags (an 2264+ * Some GSSAPI implementations use the input value of ret_flags (an
1958+ * output variable) as a means of triggering mechanism specific 2265+ * output variable) as a means of triggering mechanism specific
1959+ * features. Initializing it to zero avoids inadvertently 2266+ * features. Initializing it to zero avoids inadvertently
1960+ * activating this non-standard behaviour. 2267+ * activating this non-standard behaviour.
1961+ */ 2268+ */
1962+ 2269+
1963+ OM_uint32 ret_flags = 0; 2270+ OM_uint32 ret_flags = 0;
1964+ gss_buffer_desc gssbuf, recv_tok, msg_tok; 2271+ gss_buffer_desc gssbuf, recv_tok, msg_tok;
1965+ gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; 2272+ gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
1966+ Gssctxt *ctxt = NULL; 2273+ Gssctxt *ctxt = NULL;
1967+ u_int slen, klen, kout; 2274+ struct sshbuf *shared_secret = NULL;
1968+ u_char *kbuf; 2275+ struct sshbuf *client_pubkey = NULL;
1969+ DH *dh; 2276+ struct sshbuf *server_pubkey = NULL;
1970+ int min = -1, max = -1, nbits = -1; 2277+ struct sshbuf *empty = sshbuf_new();
1971+ const BIGNUM *pub_key, *dh_p, *dh_g;
1972+ BIGNUM *shared_secret = NULL;
1973+ BIGNUM *dh_client_pub = NULL;
1974+ int type = 0; 2278+ int type = 0;
1975+ gss_OID oid; 2279+ gss_OID oid;
1976+ char *mechs; 2280+ char *mechs;
1977+ u_char hash[SSH_DIGEST_MAX_LENGTH]; 2281+ u_char hash[SSH_DIGEST_MAX_LENGTH];
1978+ size_t hashlen; 2282+ size_t hashlen;
2283+ int r;
1979+ 2284+
1980+ /* Initialise GSSAPI */ 2285+ /* Initialise GSSAPI */
1981+ 2286+
@@ -1988,8 +2293,8 @@ index 000000000..18070f1d7
1988+ free(mechs); 2293+ free(mechs);
1989+ } 2294+ }
1990+ 2295+
1991+ debug2("%s: Identifying %s", __func__, ssh->kex->name); 2296+ debug2("%s: Identifying %s", __func__, kex->name);
1992+ oid = ssh_gssapi_id_kex(NULL, ssh->kex->name, ssh->kex->kex_type); 2297+ oid = ssh_gssapi_id_kex(NULL, kex->name, kex->kex_type);
1993+ if (oid == GSS_C_NO_OID) 2298+ if (oid == GSS_C_NO_OID)
1994+ fatal("Unknown gssapi mechanism"); 2299+ fatal("Unknown gssapi mechanism");
1995+ 2300+
@@ -1998,94 +2303,82 @@ index 000000000..18070f1d7
1998+ if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, oid)))) 2303+ if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, oid))))
1999+ fatal("Unable to acquire credentials for the server"); 2304+ fatal("Unable to acquire credentials for the server");
2000+ 2305+
2001+ switch (ssh->kex->kex_type) {
2002+ case KEX_GSS_GRP1_SHA1:
2003+ dh = dh_new_group1();
2004+ break;
2005+ case KEX_GSS_GRP14_SHA1:
2006+ dh = dh_new_group14();
2007+ break;
2008+ case KEX_GSS_GEX_SHA1:
2009+ debug("Doing group exchange");
2010+ packet_read_expect(SSH2_MSG_KEXGSS_GROUPREQ);
2011+ min = packet_get_int();
2012+ nbits = packet_get_int();
2013+ max = packet_get_int();
2014+ packet_check_eom();
2015+ if (max < min || nbits < min || max < nbits)
2016+ fatal("GSS_GEX, bad parameters: %d !< %d !< %d",
2017+ min, nbits, max);
2018+ dh = PRIVSEP(choose_dh(MAX(DH_GRP_MIN, min),
2019+ nbits, MIN(DH_GRP_MAX, max)));
2020+ if (dh == NULL)
2021+ packet_disconnect("Protocol error: no matching group found");
2022+ DH_get0_pqg(dh, &dh_p, NULL, &dh_g);
2023+
2024+ packet_start(SSH2_MSG_KEXGSS_GROUP);
2025+ packet_put_bignum2(dh_p);
2026+ packet_put_bignum2(dh_g);
2027+ packet_send();
2028+
2029+ packet_write_wait();
2030+ break;
2031+ default:
2032+ fatal("%s: Unexpected KEX type %d", __func__, ssh->kex->kex_type);
2033+ }
2034+
2035+ dh_gen_key(dh, ssh->kex->we_need * 8);
2036+
2037+ do { 2306+ do {
2038+ debug("Wait SSH2_MSG_GSSAPI_INIT"); 2307+ debug("Wait SSH2_MSG_KEXGSS_INIT");
2039+ type = packet_read(); 2308+ type = ssh_packet_read(ssh);
2040+ switch(type) { 2309+ switch(type) {
2041+ case SSH2_MSG_KEXGSS_INIT: 2310+ case SSH2_MSG_KEXGSS_INIT:
2042+ if (dh_client_pub != NULL) 2311+ if (client_pubkey != NULL)
2043+ fatal("Received KEXGSS_INIT after initialising"); 2312+ fatal("Received KEXGSS_INIT after initialising");
2044+ recv_tok.value = packet_get_string(&slen); 2313+ if ((r = ssh_gssapi_sshpkt_get_buffer_desc(ssh,
2045+ recv_tok.length = slen; 2314+ &recv_tok)) != 0 ||
2046+ 2315+ (r = sshpkt_getb_froms(ssh, &client_pubkey)) != 0 ||
2047+ if ((dh_client_pub = BN_new()) == NULL) 2316+ (r = sshpkt_get_end(ssh)) != 0)
2048+ fatal("dh_client_pub == NULL"); 2317+ fatal("sshpkt failed: %s", ssh_err(r));
2049+ 2318+
2050+ packet_get_bignum2(dh_client_pub); 2319+ switch (kex->kex_type) {
2320+ case KEX_GSS_GRP1_SHA1:
2321+ case KEX_GSS_GRP14_SHA1:
2322+ case KEX_GSS_GRP14_SHA256:
2323+ case KEX_GSS_GRP16_SHA512:
2324+ r = kex_dh_enc(kex, client_pubkey, &server_pubkey,
2325+ &shared_secret);
2326+ break;
2327+ case KEX_GSS_NISTP256_SHA256:
2328+ r = kex_ecdh_enc(kex, client_pubkey, &server_pubkey,
2329+ &shared_secret);
2330+ break;
2331+ case KEX_GSS_C25519_SHA256:
2332+ r = kex_c25519_enc(kex, client_pubkey, &server_pubkey,
2333+ &shared_secret);
2334+ break;
2335+ default:
2336+ fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type);
2337+ }
2338+ if (r != 0)
2339+ goto out;
2051+ 2340+
2052+ /* Send SSH_MSG_KEXGSS_HOSTKEY here, if we want */ 2341+ /* Send SSH_MSG_KEXGSS_HOSTKEY here, if we want */
2053+ break; 2342+ break;
2054+ case SSH2_MSG_KEXGSS_CONTINUE: 2343+ case SSH2_MSG_KEXGSS_CONTINUE:
2055+ recv_tok.value = packet_get_string(&slen); 2344+ if ((r = ssh_gssapi_sshpkt_get_buffer_desc(ssh,
2056+ recv_tok.length = slen; 2345+ &recv_tok)) != 0 ||
2346+ (r = sshpkt_get_end(ssh)) != 0)
2347+ fatal("sshpkt failed: %s", ssh_err(r));
2057+ break; 2348+ break;
2058+ default: 2349+ default:
2059+ packet_disconnect( 2350+ sshpkt_disconnect(ssh,
2060+ "Protocol error: didn't expect packet type %d", 2351+ "Protocol error: didn't expect packet type %d",
2061+ type); 2352+ type);
2062+ } 2353+ }
2063+ 2354+
2064+ maj_status = PRIVSEP(ssh_gssapi_accept_ctx(ctxt, &recv_tok, 2355+ maj_status = PRIVSEP(ssh_gssapi_accept_ctx(ctxt, &recv_tok,
2065+ &send_tok, &ret_flags)); 2356+ &send_tok, &ret_flags));
2066+ 2357+
2067+ free(recv_tok.value); 2358+ gss_release_buffer(&min_status, &recv_tok);
2068+ 2359+
2069+ if (maj_status != GSS_S_COMPLETE && send_tok.length == 0) 2360+ if (maj_status != GSS_S_COMPLETE && send_tok.length == 0)
2070+ fatal("Zero length token output when incomplete"); 2361+ fatal("Zero length token output when incomplete");
2071+ 2362+
2072+ if (dh_client_pub == NULL) 2363+ if (client_pubkey == NULL)
2073+ fatal("No client public key"); 2364+ fatal("No client public key");
2074+ 2365+
2075+ if (maj_status & GSS_S_CONTINUE_NEEDED) { 2366+ if (maj_status & GSS_S_CONTINUE_NEEDED) {
2076+ debug("Sending GSSAPI_CONTINUE"); 2367+ debug("Sending GSSAPI_CONTINUE");
2077+ packet_start(SSH2_MSG_KEXGSS_CONTINUE); 2368+ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_CONTINUE)) != 0 ||
2078+ packet_put_string(send_tok.value, send_tok.length); 2369+ (r = sshpkt_put_string(ssh, send_tok.value, send_tok.length)) != 0 ||
2079+ packet_send(); 2370+ (r = sshpkt_send(ssh)) != 0)
2371+ fatal("sshpkt failed: %s", ssh_err(r));
2080+ gss_release_buffer(&min_status, &send_tok); 2372+ gss_release_buffer(&min_status, &send_tok);
2081+ } 2373+ }
2082+ } while (maj_status & GSS_S_CONTINUE_NEEDED); 2374+ } while (maj_status & GSS_S_CONTINUE_NEEDED);
2083+ 2375+
2084+ if (GSS_ERROR(maj_status)) { 2376+ if (GSS_ERROR(maj_status)) {
2085+ if (send_tok.length > 0) { 2377+ if (send_tok.length > 0) {
2086+ packet_start(SSH2_MSG_KEXGSS_CONTINUE); 2378+ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_CONTINUE)) != 0 ||
2087+ packet_put_string(send_tok.value, send_tok.length); 2379+ (r = sshpkt_put_string(ssh, send_tok.value, send_tok.length)) != 0 ||
2088+ packet_send(); 2380+ (r = sshpkt_send(ssh)) != 0)
2381+ fatal("sshpkt failed: %s", ssh_err(r));
2089+ } 2382+ }
2090+ fatal("accept_ctx died"); 2383+ fatal("accept_ctx died");
2091+ } 2384+ }
@@ -2095,123 +2388,320 @@ index 000000000..18070f1d7
2095+ 2388+
2096+ if (!(ret_flags & GSS_C_INTEG_FLAG)) 2389+ if (!(ret_flags & GSS_C_INTEG_FLAG))
2097+ fatal("Integrity flag wasn't set"); 2390+ fatal("Integrity flag wasn't set");
2098+
2099+ if (!dh_pub_is_valid(dh, dh_client_pub))
2100+ packet_disconnect("bad client public DH value");
2101+ 2391+
2102+ klen = DH_size(dh); 2392+ hashlen = sizeof(hash);
2103+ kbuf = xmalloc(klen); 2393+ if ((r = kex_gen_hash(
2104+ kout = DH_compute_key(kbuf, dh_client_pub, dh); 2394+ kex->hash_alg,
2105+ if (kout < 0) 2395+ kex->client_version,
2106+ fatal("DH_compute_key: failed"); 2396+ kex->server_version,
2397+ kex->peer,
2398+ kex->my,
2399+ empty,
2400+ client_pubkey,
2401+ server_pubkey,
2402+ shared_secret,
2403+ hash, &hashlen)) != 0)
2404+ goto out;
2107+ 2405+
2108+ shared_secret = BN_new(); 2406+ gssbuf.value = hash;
2109+ if (shared_secret == NULL) 2407+ gssbuf.length = hashlen;
2110+ fatal("kexgss_server: BN_new failed");
2111+ 2408+
2112+ if (BN_bin2bn(kbuf, kout, shared_secret) == NULL) 2409+ if (GSS_ERROR(PRIVSEP(ssh_gssapi_sign(ctxt, &gssbuf, &msg_tok))))
2113+ fatal("kexgss_server: BN_bin2bn failed"); 2410+ fatal("Couldn't get MIC");
2114+ 2411+
2115+ memset(kbuf, 0, klen); 2412+ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_COMPLETE)) != 0 ||
2116+ free(kbuf); 2413+ (r = sshpkt_put_stringb(ssh, server_pubkey)) != 0 ||
2414+ (r = sshpkt_put_string(ssh, msg_tok.value, msg_tok.length)) != 0)
2415+ fatal("sshpkt failed: %s", ssh_err(r));
2117+ 2416+
2118+ DH_get0_key(dh, &pub_key, NULL); 2417+ if (send_tok.length != 0) {
2119+ DH_get0_pqg(dh, &dh_p, NULL, &dh_g); 2418+ if ((r = sshpkt_put_u8(ssh, 1)) != 0 || /* true */
2419+ (r = sshpkt_put_string(ssh, send_tok.value, send_tok.length)) != 0)
2420+ fatal("sshpkt failed: %s", ssh_err(r));
2421+ } else {
2422+ if ((r = sshpkt_put_u8(ssh, 0)) != 0) /* false */
2423+ fatal("sshpkt failed: %s", ssh_err(r));
2424+ }
2425+ if ((r = sshpkt_send(ssh)) != 0)
2426+ fatal("sshpkt_send failed: %s", ssh_err(r));
2120+ 2427+
2121+ hashlen = sizeof(hash); 2428+ gss_release_buffer(&min_status, &send_tok);
2122+ switch (ssh->kex->kex_type) { 2429+ gss_release_buffer(&min_status, &msg_tok);
2123+ case KEX_GSS_GRP1_SHA1: 2430+
2124+ case KEX_GSS_GRP14_SHA1: 2431+ if (gss_kex_context == NULL)
2125+ kex_dh_hash( 2432+ gss_kex_context = ctxt;
2126+ ssh->kex->hash_alg, 2433+ else
2127+ ssh->kex->client_version_string, ssh->kex->server_version_string, 2434+ ssh_gssapi_delete_ctx(&ctxt);
2128+ sshbuf_ptr(ssh->kex->peer), sshbuf_len(ssh->kex->peer), 2435+
2129+ sshbuf_ptr(ssh->kex->my), sshbuf_len(ssh->kex->my), 2436+ if ((r = kex_derive_keys(ssh, hash, hashlen, shared_secret)) == 0)
2130+ NULL, 0, /* Change this if we start sending host keys */ 2437+ r = kex_send_newkeys(ssh);
2131+ dh_client_pub, pub_key, shared_secret, 2438+
2132+ hash, &hashlen 2439+ /* If this was a rekey, then save out any delegated credentials we
2133+ ); 2440+ * just exchanged. */
2134+ break; 2441+ if (options.gss_store_rekey)
2135+ case KEX_GSS_GEX_SHA1: 2442+ ssh_gssapi_rekey_creds();
2136+ kexgex_hash( 2443+out:
2137+ ssh->kex->hash_alg, 2444+ sshbuf_free(empty);
2138+ ssh->kex->client_version_string, ssh->kex->server_version_string, 2445+ explicit_bzero(hash, sizeof(hash));
2139+ sshbuf_ptr(ssh->kex->peer), sshbuf_len(ssh->kex->peer), 2446+ sshbuf_free(shared_secret);
2140+ sshbuf_ptr(ssh->kex->my), sshbuf_len(ssh->kex->my), 2447+ sshbuf_free(client_pubkey);
2141+ NULL, 0, 2448+ sshbuf_free(server_pubkey);
2142+ min, nbits, max, 2449+ return r;
2143+ dh_p, dh_g, 2450+}
2144+ dh_client_pub, 2451+
2145+ pub_key, 2452+int
2146+ shared_secret, 2453+kexgssgex_server(struct ssh *ssh)
2147+ hash, &hashlen 2454+{
2148+ ); 2455+ struct kex *kex = ssh->kex;
2149+ break; 2456+ OM_uint32 maj_status, min_status;
2150+ default: 2457+
2151+ fatal("%s: Unexpected KEX type %d", __func__, ssh->kex->kex_type); 2458+ /*
2459+ * Some GSSAPI implementations use the input value of ret_flags (an
2460+ * output variable) as a means of triggering mechanism specific
2461+ * features. Initializing it to zero avoids inadvertently
2462+ * activating this non-standard behaviour.
2463+ */
2464+
2465+ OM_uint32 ret_flags = 0;
2466+ gss_buffer_desc gssbuf, recv_tok, msg_tok;
2467+ gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
2468+ Gssctxt *ctxt = NULL;
2469+ struct sshbuf *shared_secret = NULL;
2470+ int type = 0;
2471+ gss_OID oid;
2472+ char *mechs;
2473+ u_char hash[SSH_DIGEST_MAX_LENGTH];
2474+ size_t hashlen;
2475+ BIGNUM *dh_client_pub = NULL;
2476+ const BIGNUM *pub_key, *dh_p, *dh_g;
2477+ int min = -1, max = -1, nbits = -1;
2478+ int cmin = -1, cmax = -1; /* client proposal */
2479+ struct sshbuf *empty = sshbuf_new();
2480+ int r;
2481+
2482+ /* Initialise GSSAPI */
2483+
2484+ /* If we're rekeying, privsep means that some of the private structures
2485+ * in the GSSAPI code are no longer available. This kludges them back
2486+ * into life
2487+ */
2488+ if (!ssh_gssapi_oid_table_ok())
2489+ if ((mechs = ssh_gssapi_server_mechanisms()))
2490+ free(mechs);
2491+
2492+ debug2("%s: Identifying %s", __func__, kex->name);
2493+ oid = ssh_gssapi_id_kex(NULL, kex->name, kex->kex_type);
2494+ if (oid == GSS_C_NO_OID)
2495+ fatal("Unknown gssapi mechanism");
2496+
2497+ debug2("%s: Acquiring credentials", __func__);
2498+
2499+ if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, oid))))
2500+ fatal("Unable to acquire credentials for the server");
2501+
2502+ /* 5. S generates an ephemeral key pair (do the allocations early) */
2503+ debug("Doing group exchange");
2504+ ssh_packet_read_expect(ssh, SSH2_MSG_KEXGSS_GROUPREQ);
2505+ /* store client proposal to provide valid signature */
2506+ if ((r = sshpkt_get_u32(ssh, &cmin)) != 0 ||
2507+ (r = sshpkt_get_u32(ssh, &nbits)) != 0 ||
2508+ (r = sshpkt_get_u32(ssh, &cmax)) != 0 ||
2509+ (r = sshpkt_get_end(ssh)) != 0)
2510+ fatal("sshpkt failed: %s", ssh_err(r));
2511+ kex->nbits = nbits;
2512+ kex->min = cmin;
2513+ kex->max = cmax;
2514+ min = MAX(DH_GRP_MIN, cmin);
2515+ max = MIN(DH_GRP_MAX, cmax);
2516+ nbits = MAXIMUM(DH_GRP_MIN, nbits);
2517+ nbits = MINIMUM(DH_GRP_MAX, nbits);
2518+ if (max < min || nbits < min || max < nbits)
2519+ fatal("GSS_GEX, bad parameters: %d !< %d !< %d",
2520+ min, nbits, max);
2521+ kex->dh = PRIVSEP(choose_dh(min, nbits, max));
2522+ if (kex->dh == NULL) {
2523+ sshpkt_disconnect(ssh, "Protocol error: no matching group found");
2524+ fatal("Protocol error: no matching group found");
2152+ } 2525+ }
2153+ 2526+
2154+ BN_clear_free(dh_client_pub); 2527+ DH_get0_pqg(kex->dh, &dh_p, NULL, &dh_g);
2528+ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_GROUP)) != 0 ||
2529+ (r = sshpkt_put_bignum2(ssh, dh_p)) != 0 ||
2530+ (r = sshpkt_put_bignum2(ssh, dh_g)) != 0 ||
2531+ (r = sshpkt_send(ssh)) != 0)
2532+ fatal("sshpkt failed: %s", ssh_err(r));
2533+
2534+ if ((r = ssh_packet_write_wait(ssh)) != 0)
2535+ fatal("ssh_packet_write_wait: %s", ssh_err(r));
2536+
2537+ /* Compute our exchange value in parallel with the client */
2538+ if ((r = dh_gen_key(kex->dh, kex->we_need * 8)) != 0)
2539+ goto out;
2540+
2541+ do {
2542+ debug("Wait SSH2_MSG_GSSAPI_INIT");
2543+ type = ssh_packet_read(ssh);
2544+ switch(type) {
2545+ case SSH2_MSG_KEXGSS_INIT:
2546+ if (dh_client_pub != NULL)
2547+ fatal("Received KEXGSS_INIT after initialising");
2548+ if ((r = ssh_gssapi_sshpkt_get_buffer_desc(ssh,
2549+ &recv_tok)) != 0 ||
2550+ (r = sshpkt_get_bignum2(ssh, &dh_client_pub)) != 0 ||
2551+ (r = sshpkt_get_end(ssh)) != 0)
2552+ fatal("sshpkt failed: %s", ssh_err(r));
2553+
2554+ /* Send SSH_MSG_KEXGSS_HOSTKEY here, if we want */
2555+ break;
2556+ case SSH2_MSG_KEXGSS_CONTINUE:
2557+ if ((r = ssh_gssapi_sshpkt_get_buffer_desc(ssh,
2558+ &recv_tok)) != 0 ||
2559+ (r = sshpkt_get_end(ssh)) != 0)
2560+ fatal("sshpkt failed: %s", ssh_err(r));
2561+ break;
2562+ default:
2563+ sshpkt_disconnect(ssh,
2564+ "Protocol error: didn't expect packet type %d",
2565+ type);
2566+ }
2567+
2568+ maj_status = PRIVSEP(ssh_gssapi_accept_ctx(ctxt, &recv_tok,
2569+ &send_tok, &ret_flags));
2570+
2571+ gss_release_buffer(&min_status, &recv_tok);
2572+
2573+ if (maj_status != GSS_S_COMPLETE && send_tok.length == 0)
2574+ fatal("Zero length token output when incomplete");
2575+
2576+ if (dh_client_pub == NULL)
2577+ fatal("No client public key");
2578+
2579+ if (maj_status & GSS_S_CONTINUE_NEEDED) {
2580+ debug("Sending GSSAPI_CONTINUE");
2581+ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_CONTINUE)) != 0 ||
2582+ (r = sshpkt_put_string(ssh, send_tok.value, send_tok.length)) != 0 ||
2583+ (r = sshpkt_send(ssh)) != 0)
2584+ fatal("sshpkt failed: %s", ssh_err(r));
2585+ gss_release_buffer(&min_status, &send_tok);
2586+ }
2587+ } while (maj_status & GSS_S_CONTINUE_NEEDED);
2588+
2589+ if (GSS_ERROR(maj_status)) {
2590+ if (send_tok.length > 0) {
2591+ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_CONTINUE)) != 0 ||
2592+ (r = sshpkt_put_string(ssh, send_tok.value, send_tok.length)) != 0 ||
2593+ (r = sshpkt_send(ssh)) != 0)
2594+ fatal("sshpkt failed: %s", ssh_err(r));
2595+ }
2596+ fatal("accept_ctx died");
2597+ }
2155+ 2598+
2156+ if (ssh->kex->session_id == NULL) { 2599+ if (!(ret_flags & GSS_C_MUTUAL_FLAG))
2157+ ssh->kex->session_id_len = hashlen; 2600+ fatal("Mutual Authentication flag wasn't set");
2158+ ssh->kex->session_id = xmalloc(ssh->kex->session_id_len); 2601+
2159+ memcpy(ssh->kex->session_id, hash, ssh->kex->session_id_len); 2602+ if (!(ret_flags & GSS_C_INTEG_FLAG))
2603+ fatal("Integrity flag wasn't set");
2604+
2605+ /* calculate shared secret */
2606+ if ((shared_secret = sshbuf_new()) == NULL) {
2607+ r = SSH_ERR_ALLOC_FAIL;
2608+ goto out;
2160+ } 2609+ }
2610+ if ((r = kex_dh_compute_key(kex, dh_client_pub, shared_secret)) != 0)
2611+ goto out;
2612+
2613+ DH_get0_key(kex->dh, &pub_key, NULL);
2614+ DH_get0_pqg(kex->dh, &dh_p, NULL, &dh_g);
2615+ hashlen = sizeof(hash);
2616+ if ((r = kexgex_hash(
2617+ kex->hash_alg,
2618+ kex->client_version,
2619+ kex->server_version,
2620+ kex->peer,
2621+ kex->my,
2622+ empty,
2623+ cmin, nbits, cmax,
2624+ dh_p, dh_g,
2625+ dh_client_pub,
2626+ pub_key,
2627+ sshbuf_ptr(shared_secret), sshbuf_len(shared_secret),
2628+ hash, &hashlen)) != 0)
2629+ fatal("kexgex_hash failed: %s", ssh_err(r));
2161+ 2630+
2162+ gssbuf.value = hash; 2631+ gssbuf.value = hash;
2163+ gssbuf.length = hashlen; 2632+ gssbuf.length = hashlen;
2164+ 2633+
2165+ if (GSS_ERROR(PRIVSEP(ssh_gssapi_sign(ctxt,&gssbuf,&msg_tok)))) 2634+ if (GSS_ERROR(PRIVSEP(ssh_gssapi_sign(ctxt, &gssbuf, &msg_tok))))
2166+ fatal("Couldn't get MIC"); 2635+ fatal("Couldn't get MIC");
2167+ 2636+
2168+ packet_start(SSH2_MSG_KEXGSS_COMPLETE); 2637+ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_COMPLETE)) != 0 ||
2169+ packet_put_bignum2(pub_key); 2638+ (r = sshpkt_put_bignum2(ssh, pub_key)) != 0 ||
2170+ packet_put_string(msg_tok.value,msg_tok.length); 2639+ (r = sshpkt_put_string(ssh, msg_tok.value, msg_tok.length)) != 0)
2640+ fatal("sshpkt failed: %s", ssh_err(r));
2171+ 2641+
2172+ if (send_tok.length != 0) { 2642+ if (send_tok.length != 0) {
2173+ packet_put_char(1); /* true */ 2643+ if ((r = sshpkt_put_u8(ssh, 1)) != 0 || /* true */
2174+ packet_put_string(send_tok.value, send_tok.length); 2644+ (r = sshpkt_put_string(ssh, send_tok.value, send_tok.length)) != 0)
2645+ fatal("sshpkt failed: %s", ssh_err(r));
2175+ } else { 2646+ } else {
2176+ packet_put_char(0); /* false */ 2647+ if ((r = sshpkt_put_u8(ssh, 0)) != 0) /* false */
2648+ fatal("sshpkt failed: %s", ssh_err(r));
2177+ } 2649+ }
2178+ packet_send(); 2650+ if ((r = sshpkt_send(ssh)) != 0)
2651+ fatal("sshpkt failed: %s", ssh_err(r));
2179+ 2652+
2180+ gss_release_buffer(&min_status, &send_tok); 2653+ gss_release_buffer(&min_status, &send_tok);
2181+ gss_release_buffer(&min_status, &msg_tok); 2654+ gss_release_buffer(&min_status, &msg_tok);
2182+ 2655+
2183+ if (gss_kex_context == NULL) 2656+ if (gss_kex_context == NULL)
2184+ gss_kex_context = ctxt; 2657+ gss_kex_context = ctxt;
2185+ else 2658+ else
2186+ ssh_gssapi_delete_ctx(&ctxt); 2659+ ssh_gssapi_delete_ctx(&ctxt);
2187+ 2660+
2188+ DH_free(dh); 2661+ /* Finally derive the keys and send them */
2189+ 2662+ if ((r = kex_derive_keys(ssh, hash, hashlen, shared_secret)) == 0)
2190+ kex_derive_keys_bn(ssh, hash, hashlen, shared_secret); 2663+ r = kex_send_newkeys(ssh);
2191+ BN_clear_free(shared_secret);
2192+ kex_send_newkeys(ssh);
2193+ 2664+
2194+ /* If this was a rekey, then save out any delegated credentials we 2665+ /* If this was a rekey, then save out any delegated credentials we
2195+ * just exchanged. */ 2666+ * just exchanged. */
2196+ if (options.gss_store_rekey) 2667+ if (options.gss_store_rekey)
2197+ ssh_gssapi_rekey_creds(); 2668+ ssh_gssapi_rekey_creds();
2198+ return 0; 2669+out:
2670+ sshbuf_free(empty);
2671+ explicit_bzero(hash, sizeof(hash));
2672+ DH_free(kex->dh);
2673+ kex->dh = NULL;
2674+ BN_clear_free(dh_client_pub);
2675+ sshbuf_free(shared_secret);
2676+ return r;
2199+} 2677+}
2200+#endif /* GSSAPI */ 2678+#endif /* defined(GSSAPI) && defined(WITH_OPENSSL) */
2679diff --git a/mac.c b/mac.c
2680index 51dc11d76..3d11eba62 100644
2681--- a/mac.c
2682+++ b/mac.c
2683@@ -29,6 +29,7 @@
2684
2685 #include <string.h>
2686 #include <stdio.h>
2687+#include <stdlib.h>
2688
2689 #include "digest.h"
2690 #include "hmac.h"
2201diff --git a/monitor.c b/monitor.c 2691diff --git a/monitor.c b/monitor.c
2202index 531b2993a..eabc1e89b 100644 2692index 60e529444..0766d6ef5 100644
2203--- a/monitor.c 2693--- a/monitor.c
2204+++ b/monitor.c 2694+++ b/monitor.c
2205@@ -145,6 +145,8 @@ int mm_answer_gss_setup_ctx(int, struct sshbuf *); 2695@@ -147,6 +147,8 @@ int mm_answer_gss_setup_ctx(struct ssh *, int, struct sshbuf *);
2206 int mm_answer_gss_accept_ctx(int, struct sshbuf *); 2696 int mm_answer_gss_accept_ctx(struct ssh *, int, struct sshbuf *);
2207 int mm_answer_gss_userok(int, struct sshbuf *); 2697 int mm_answer_gss_userok(struct ssh *, int, struct sshbuf *);
2208 int mm_answer_gss_checkmic(int, struct sshbuf *); 2698 int mm_answer_gss_checkmic(struct ssh *, int, struct sshbuf *);
2209+int mm_answer_gss_sign(int, struct sshbuf *); 2699+int mm_answer_gss_sign(struct ssh *, int, struct sshbuf *);
2210+int mm_answer_gss_updatecreds(int, struct sshbuf *); 2700+int mm_answer_gss_updatecreds(struct ssh *, int, struct sshbuf *);
2211 #endif 2701 #endif
2212 2702
2213 #ifdef SSH_AUDIT_EVENTS 2703 #ifdef SSH_AUDIT_EVENTS
2214@@ -215,11 +217,18 @@ struct mon_table mon_dispatch_proto20[] = { 2704@@ -219,11 +221,18 @@ struct mon_table mon_dispatch_proto20[] = {
2215 {MONITOR_REQ_GSSSTEP, 0, mm_answer_gss_accept_ctx}, 2705 {MONITOR_REQ_GSSSTEP, 0, mm_answer_gss_accept_ctx},
2216 {MONITOR_REQ_GSSUSEROK, MON_ONCE|MON_AUTHDECIDE, mm_answer_gss_userok}, 2706 {MONITOR_REQ_GSSUSEROK, MON_ONCE|MON_AUTHDECIDE, mm_answer_gss_userok},
2217 {MONITOR_REQ_GSSCHECKMIC, MON_ONCE, mm_answer_gss_checkmic}, 2707 {MONITOR_REQ_GSSCHECKMIC, MON_ONCE, mm_answer_gss_checkmic},
@@ -2230,7 +2720,7 @@ index 531b2993a..eabc1e89b 100644
2230 #ifdef WITH_OPENSSL 2720 #ifdef WITH_OPENSSL
2231 {MONITOR_REQ_MODULI, 0, mm_answer_moduli}, 2721 {MONITOR_REQ_MODULI, 0, mm_answer_moduli},
2232 #endif 2722 #endif
2233@@ -289,6 +298,10 @@ monitor_child_preauth(Authctxt *_authctxt, struct monitor *pmonitor) 2723@@ -292,6 +301,10 @@ monitor_child_preauth(struct ssh *ssh, struct monitor *pmonitor)
2234 /* Permit requests for moduli and signatures */ 2724 /* Permit requests for moduli and signatures */
2235 monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); 2725 monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1);
2236 monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); 2726 monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1);
@@ -2241,32 +2731,36 @@ index 531b2993a..eabc1e89b 100644
2241 2731
2242 /* The first few requests do not require asynchronous access */ 2732 /* The first few requests do not require asynchronous access */
2243 while (!authenticated) { 2733 while (!authenticated) {
2244@@ -401,6 +414,10 @@ monitor_child_postauth(struct monitor *pmonitor) 2734@@ -405,6 +418,10 @@ monitor_child_postauth(struct ssh *ssh, struct monitor *pmonitor)
2245 monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); 2735 monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1);
2246 monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); 2736 monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1);
2247 monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); 2737 monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1);
2248+#ifdef GSSAPI 2738+#ifdef GSSAPI
2249+ /* and for the GSSAPI key exchange */ 2739+ /* and for the GSSAPI key exchange */
2250+ monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1); 2740+ monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1);
2251+#endif 2741+#endif
2252 2742
2253 if (auth_opts->permit_pty_flag) { 2743 if (auth_opts->permit_pty_flag) {
2254 monitor_permit(mon_dispatch, MONITOR_REQ_PTY, 1); 2744 monitor_permit(mon_dispatch, MONITOR_REQ_PTY, 1);
2255@@ -1666,6 +1683,13 @@ monitor_apply_keystate(struct monitor *pmonitor) 2745@@ -1687,6 +1704,17 @@ monitor_apply_keystate(struct ssh *ssh, struct monitor *pmonitor)
2746 # ifdef OPENSSL_HAS_ECC
2747 kex->kex[KEX_ECDH_SHA2] = kex_gen_server;
2256 # endif 2748 # endif
2257 #endif /* WITH_OPENSSL */ 2749+# ifdef GSSAPI
2258 kex->kex[KEX_C25519_SHA256] = kexc25519_server;
2259+#ifdef GSSAPI
2260+ if (options.gss_keyex) { 2750+ if (options.gss_keyex) {
2261+ kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server; 2751+ kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server;
2262+ kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_server; 2752+ kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_server;
2263+ kex->kex[KEX_GSS_GEX_SHA1] = kexgss_server; 2753+ kex->kex[KEX_GSS_GRP14_SHA256] = kexgss_server;
2754+ kex->kex[KEX_GSS_GRP16_SHA512] = kexgss_server;
2755+ kex->kex[KEX_GSS_GEX_SHA1] = kexgssgex_server;
2756+ kex->kex[KEX_GSS_NISTP256_SHA256] = kexgss_server;
2757+ kex->kex[KEX_GSS_C25519_SHA256] = kexgss_server;
2264+ } 2758+ }
2265+#endif 2759+# endif
2266 kex->load_host_public_key=&get_hostkey_public_by_type; 2760 #endif /* WITH_OPENSSL */
2267 kex->load_host_private_key=&get_hostkey_private_by_type; 2761 kex->kex[KEX_C25519_SHA256] = kex_gen_server;
2268 kex->host_key_index=&get_hostkey_index; 2762 kex->kex[KEX_KEM_SNTRUP4591761X25519_SHA512] = kex_gen_server;
2269@@ -1756,8 +1780,8 @@ mm_answer_gss_setup_ctx(int sock, struct sshbuf *m) 2763@@ -1780,8 +1808,8 @@ mm_answer_gss_setup_ctx(struct ssh *ssh, int sock, struct sshbuf *m)
2270 u_char *p; 2764 u_char *p;
2271 int r; 2765 int r;
2272 2766
@@ -2277,7 +2771,7 @@ index 531b2993a..eabc1e89b 100644
2277 2771
2278 if ((r = sshbuf_get_string(m, &p, &len)) != 0) 2772 if ((r = sshbuf_get_string(m, &p, &len)) != 0)
2279 fatal("%s: buffer error: %s", __func__, ssh_err(r)); 2773 fatal("%s: buffer error: %s", __func__, ssh_err(r));
2280@@ -1789,8 +1813,8 @@ mm_answer_gss_accept_ctx(int sock, struct sshbuf *m) 2774@@ -1813,8 +1841,8 @@ mm_answer_gss_accept_ctx(struct ssh *ssh, int sock, struct sshbuf *m)
2281 OM_uint32 flags = 0; /* GSI needs this */ 2775 OM_uint32 flags = 0; /* GSI needs this */
2282 int r; 2776 int r;
2283 2777
@@ -2288,7 +2782,7 @@ index 531b2993a..eabc1e89b 100644
2288 2782
2289 if ((r = ssh_gssapi_get_buffer_desc(m, &in)) != 0) 2783 if ((r = ssh_gssapi_get_buffer_desc(m, &in)) != 0)
2290 fatal("%s: buffer error: %s", __func__, ssh_err(r)); 2784 fatal("%s: buffer error: %s", __func__, ssh_err(r));
2291@@ -1810,6 +1834,7 @@ mm_answer_gss_accept_ctx(int sock, struct sshbuf *m) 2785@@ -1834,6 +1862,7 @@ mm_answer_gss_accept_ctx(struct ssh *ssh, int sock, struct sshbuf *m)
2292 monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 0); 2786 monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 0);
2293 monitor_permit(mon_dispatch, MONITOR_REQ_GSSUSEROK, 1); 2787 monitor_permit(mon_dispatch, MONITOR_REQ_GSSUSEROK, 1);
2294 monitor_permit(mon_dispatch, MONITOR_REQ_GSSCHECKMIC, 1); 2788 monitor_permit(mon_dispatch, MONITOR_REQ_GSSCHECKMIC, 1);
@@ -2296,7 +2790,7 @@ index 531b2993a..eabc1e89b 100644
2296 } 2790 }
2297 return (0); 2791 return (0);
2298 } 2792 }
2299@@ -1821,8 +1846,8 @@ mm_answer_gss_checkmic(int sock, struct sshbuf *m) 2793@@ -1845,8 +1874,8 @@ mm_answer_gss_checkmic(struct ssh *ssh, int sock, struct sshbuf *m)
2300 OM_uint32 ret; 2794 OM_uint32 ret;
2301 int r; 2795 int r;
2302 2796
@@ -2307,8 +2801,12 @@ index 531b2993a..eabc1e89b 100644
2307 2801
2308 if ((r = ssh_gssapi_get_buffer_desc(m, &gssbuf)) != 0 || 2802 if ((r = ssh_gssapi_get_buffer_desc(m, &gssbuf)) != 0 ||
2309 (r = ssh_gssapi_get_buffer_desc(m, &mic)) != 0) 2803 (r = ssh_gssapi_get_buffer_desc(m, &mic)) != 0)
2310@@ -1851,10 +1876,11 @@ mm_answer_gss_userok(int sock, struct sshbuf *m) 2804@@ -1872,13 +1901,17 @@ mm_answer_gss_checkmic(struct ssh *ssh, int sock, struct sshbuf *m)
2311 int r, authenticated; 2805 int
2806 mm_answer_gss_userok(struct ssh *ssh, int sock, struct sshbuf *m)
2807 {
2808- int r, authenticated;
2809+ int r, authenticated, kex;
2312 const char *displayname; 2810 const char *displayname;
2313 2811
2314- if (!options.gss_authentication) 2812- if (!options.gss_authentication)
@@ -2317,24 +2815,40 @@ index 531b2993a..eabc1e89b 100644
2317+ fatal("%s: GSSAPI not enabled", __func__); 2815+ fatal("%s: GSSAPI not enabled", __func__);
2318 2816
2319- authenticated = authctxt->valid && ssh_gssapi_userok(authctxt->user); 2817- authenticated = authctxt->valid && ssh_gssapi_userok(authctxt->user);
2320+ authenticated = authctxt->valid && 2818+ if ((r = sshbuf_get_u32(m, &kex)) != 0)
2321+ ssh_gssapi_userok(authctxt->user, authctxt->pw); 2819+ fatal("%s: buffer error: %s", __func__, ssh_err(r));
2820+
2821+ authenticated = authctxt->valid &&
2822+ ssh_gssapi_userok(authctxt->user, authctxt->pw, kex);
2322 2823
2323 sshbuf_reset(m); 2824 sshbuf_reset(m);
2324 if ((r = sshbuf_put_u32(m, authenticated)) != 0) 2825 if ((r = sshbuf_put_u32(m, authenticated)) != 0)
2325@@ -1871,5 +1897,83 @@ mm_answer_gss_userok(int sock, struct sshbuf *m) 2826@@ -1887,7 +1920,11 @@ mm_answer_gss_userok(struct ssh *ssh, int sock, struct sshbuf *m)
2827 debug3("%s: sending result %d", __func__, authenticated);
2828 mm_request_send(sock, MONITOR_ANS_GSSUSEROK, m);
2829
2830- auth_method = "gssapi-with-mic";
2831+ if (kex) {
2832+ auth_method = "gssapi-keyex";
2833+ } else {
2834+ auth_method = "gssapi-with-mic";
2835+ }
2836
2837 if ((displayname = ssh_gssapi_displayname()) != NULL)
2838 auth2_record_info(authctxt, "%s", displayname);
2839@@ -1895,5 +1932,85 @@ mm_answer_gss_userok(struct ssh *ssh, int sock, struct sshbuf *m)
2326 /* Monitor loop will terminate if authenticated */ 2840 /* Monitor loop will terminate if authenticated */
2327 return (authenticated); 2841 return (authenticated);
2328 } 2842 }
2329+ 2843+
2330+int 2844+int
2331+mm_answer_gss_sign(int socket, struct sshbuf *m) 2845+mm_answer_gss_sign(struct ssh *ssh, int socket, struct sshbuf *m)
2332+{ 2846+{
2333+ gss_buffer_desc data; 2847+ gss_buffer_desc data;
2334+ gss_buffer_desc hash = GSS_C_EMPTY_BUFFER; 2848+ gss_buffer_desc hash = GSS_C_EMPTY_BUFFER;
2335+ OM_uint32 major, minor; 2849+ OM_uint32 major, minor;
2336+ size_t len; 2850+ size_t len;
2337+ u_char *p; 2851+ u_char *p = NULL;
2338+ int r; 2852+ int r;
2339+ 2853+
2340+ if (!options.gss_authentication && !options.gss_keyex) 2854+ if (!options.gss_authentication && !options.gss_keyex)
@@ -2344,8 +2858,9 @@ index 531b2993a..eabc1e89b 100644
2344+ fatal("%s: buffer error: %s", __func__, ssh_err(r)); 2858+ fatal("%s: buffer error: %s", __func__, ssh_err(r));
2345+ data.value = p; 2859+ data.value = p;
2346+ data.length = len; 2860+ data.length = len;
2347+ if (data.length != 20) 2861+ /* Lengths of SHA-1, SHA-256 and SHA-512 hashes that are used */
2348+ fatal("%s: data length incorrect: %d", __func__, 2862+ if (data.length != 20 && data.length != 32 && data.length != 64)
2863+ fatal("%s: data length incorrect: %d", __func__,
2349+ (int) data.length); 2864+ (int) data.length);
2350+ 2865+
2351+ /* Save the session ID on the first time around */ 2866+ /* Save the session ID on the first time around */
@@ -2359,6 +2874,7 @@ index 531b2993a..eabc1e89b 100644
2359+ free(data.value); 2874+ free(data.value);
2360+ 2875+
2361+ sshbuf_reset(m); 2876+ sshbuf_reset(m);
2877+
2362+ if ((r = sshbuf_put_u32(m, major)) != 0 || 2878+ if ((r = sshbuf_put_u32(m, major)) != 0 ||
2363+ (r = sshbuf_put_string(m, hash.value, hash.length)) != 0) 2879+ (r = sshbuf_put_string(m, hash.value, hash.length)) != 0)
2364+ fatal("%s: buffer error: %s", __func__, ssh_err(r)); 2880+ fatal("%s: buffer error: %s", __func__, ssh_err(r));
@@ -2369,7 +2885,7 @@ index 531b2993a..eabc1e89b 100644
2369+ 2885+
2370+ /* Turn on getpwnam permissions */ 2886+ /* Turn on getpwnam permissions */
2371+ monitor_permit(mon_dispatch, MONITOR_REQ_PWNAM, 1); 2887+ monitor_permit(mon_dispatch, MONITOR_REQ_PWNAM, 1);
2372+ 2888+
2373+ /* And credential updating, for when rekeying */ 2889+ /* And credential updating, for when rekeying */
2374+ monitor_permit(mon_dispatch, MONITOR_REQ_GSSUPCREDS, 1); 2890+ monitor_permit(mon_dispatch, MONITOR_REQ_GSSUPCREDS, 1);
2375+ 2891+
@@ -2377,16 +2893,16 @@ index 531b2993a..eabc1e89b 100644
2377+} 2893+}
2378+ 2894+
2379+int 2895+int
2380+mm_answer_gss_updatecreds(int socket, struct sshbuf *m) { 2896+mm_answer_gss_updatecreds(struct ssh *ssh, int socket, struct sshbuf *m) {
2381+ ssh_gssapi_ccache store; 2897+ ssh_gssapi_ccache store;
2382+ int r, ok; 2898+ int r, ok;
2383+ 2899+
2384+ if (!options.gss_authentication && !options.gss_keyex) 2900+ if (!options.gss_authentication && !options.gss_keyex)
2385+ fatal("%s: GSSAPI not enabled", __func__); 2901+ fatal("%s: GSSAPI not enabled", __func__);
2386+ 2902+
2387+ if ((r = sshbuf_get_cstring(m, &store.filename, NULL)) != 0 || 2903+ if ((r = sshbuf_get_string(m, (u_char **)&store.filename, NULL)) != 0 ||
2388+ (r = sshbuf_get_cstring(m, &store.envvar, NULL)) != 0 || 2904+ (r = sshbuf_get_string(m, (u_char **)&store.envvar, NULL)) != 0 ||
2389+ (r = sshbuf_get_cstring(m, &store.envval, NULL)) != 0) 2905+ (r = sshbuf_get_string(m, (u_char **)&store.envval, NULL)) != 0)
2390+ fatal("%s: buffer error: %s", __func__, ssh_err(r)); 2906+ fatal("%s: buffer error: %s", __func__, ssh_err(r));
2391+ 2907+
2392+ ok = ssh_gssapi_update_creds(&store); 2908+ ok = ssh_gssapi_update_creds(&store);
@@ -2407,33 +2923,40 @@ index 531b2993a..eabc1e89b 100644
2407 #endif /* GSSAPI */ 2923 #endif /* GSSAPI */
2408 2924
2409diff --git a/monitor.h b/monitor.h 2925diff --git a/monitor.h b/monitor.h
2410index 16047299f..44fbed589 100644 2926index 683e5e071..2b1a2d590 100644
2411--- a/monitor.h 2927--- a/monitor.h
2412+++ b/monitor.h 2928+++ b/monitor.h
2413@@ -63,6 +63,9 @@ enum monitor_reqtype { 2929@@ -63,6 +63,8 @@ enum monitor_reqtype {
2414 MONITOR_REQ_PAM_FREE_CTX = 110, MONITOR_ANS_PAM_FREE_CTX = 111, 2930 MONITOR_REQ_PAM_FREE_CTX = 110, MONITOR_ANS_PAM_FREE_CTX = 111,
2415 MONITOR_REQ_AUDIT_EVENT = 112, MONITOR_REQ_AUDIT_COMMAND = 113, 2931 MONITOR_REQ_AUDIT_EVENT = 112, MONITOR_REQ_AUDIT_COMMAND = 113,
2416 2932
2417+ MONITOR_REQ_GSSSIGN = 150, MONITOR_ANS_GSSSIGN = 151, 2933+ MONITOR_REQ_GSSSIGN = 150, MONITOR_ANS_GSSSIGN = 151,
2418+ MONITOR_REQ_GSSUPCREDS = 152, MONITOR_ANS_GSSUPCREDS = 153, 2934+ MONITOR_REQ_GSSUPCREDS = 152, MONITOR_ANS_GSSUPCREDS = 153,
2419+
2420 }; 2935 };
2421 2936
2422 struct monitor { 2937 struct ssh;
2423diff --git a/monitor_wrap.c b/monitor_wrap.c 2938diff --git a/monitor_wrap.c b/monitor_wrap.c
2424index 732fb3476..1865a122a 100644 2939index 186e8f022..8e4c1c1f8 100644
2425--- a/monitor_wrap.c 2940--- a/monitor_wrap.c
2426+++ b/monitor_wrap.c 2941+++ b/monitor_wrap.c
2427@@ -984,7 +984,7 @@ mm_ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic) 2942@@ -978,13 +978,15 @@ mm_ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic)
2428 } 2943 }
2429 2944
2430 int 2945 int
2431-mm_ssh_gssapi_userok(char *user) 2946-mm_ssh_gssapi_userok(char *user)
2432+mm_ssh_gssapi_userok(char *user, struct passwd *pw) 2947+mm_ssh_gssapi_userok(char *user, struct passwd *pw, int kex)
2433 { 2948 {
2434 struct sshbuf *m; 2949 struct sshbuf *m;
2435 int r, authenticated = 0; 2950 int r, authenticated = 0;
2436@@ -1003,4 +1003,55 @@ mm_ssh_gssapi_userok(char *user) 2951
2952 if ((m = sshbuf_new()) == NULL)
2953 fatal("%s: sshbuf_new failed", __func__);
2954+ if ((r = sshbuf_put_u32(m, kex)) != 0)
2955+ fatal("%s: buffer error: %s", __func__, ssh_err(r));
2956
2957 mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSUSEROK, m);
2958 mm_request_receive_expect(pmonitor->m_recvfd,
2959@@ -997,4 +999,57 @@ mm_ssh_gssapi_userok(char *user)
2437 debug3("%s: user %sauthenticated",__func__, authenticated ? "" : "not "); 2960 debug3("%s: user %sauthenticated",__func__, authenticated ? "" : "not ");
2438 return (authenticated); 2961 return (authenticated);
2439 } 2962 }
@@ -2459,7 +2982,7 @@ index 732fb3476..1865a122a 100644
2459+ 2982+
2460+ sshbuf_free(m); 2983+ sshbuf_free(m);
2461+ 2984+
2462+ return(major); 2985+ return (major);
2463+} 2986+}
2464+ 2987+
2465+int 2988+int
@@ -2470,6 +2993,7 @@ index 732fb3476..1865a122a 100644
2470+ 2993+
2471+ if ((m = sshbuf_new()) == NULL) 2994+ if ((m = sshbuf_new()) == NULL)
2472+ fatal("%s: sshbuf_new failed", __func__); 2995+ fatal("%s: sshbuf_new failed", __func__);
2996+
2473+ if ((r = sshbuf_put_cstring(m, 2997+ if ((r = sshbuf_put_cstring(m,
2474+ store->filename ? store->filename : "")) != 0 || 2998+ store->filename ? store->filename : "")) != 0 ||
2475+ (r = sshbuf_put_cstring(m, 2999+ (r = sshbuf_put_cstring(m,
@@ -2483,6 +3007,7 @@ index 732fb3476..1865a122a 100644
2483+ 3007+
2484+ if ((r = sshbuf_get_u32(m, &ok)) != 0) 3008+ if ((r = sshbuf_get_u32(m, &ok)) != 0)
2485+ fatal("%s: buffer error: %s", __func__, ssh_err(r)); 3009+ fatal("%s: buffer error: %s", __func__, ssh_err(r));
3010+
2486+ sshbuf_free(m); 3011+ sshbuf_free(m);
2487+ 3012+
2488+ return (ok); 3013+ return (ok);
@@ -2490,61 +3015,43 @@ index 732fb3476..1865a122a 100644
2490+ 3015+
2491 #endif /* GSSAPI */ 3016 #endif /* GSSAPI */
2492diff --git a/monitor_wrap.h b/monitor_wrap.h 3017diff --git a/monitor_wrap.h b/monitor_wrap.h
2493index 644da081d..7f93144ff 100644 3018index fdebb3aa4..69164a8c0 100644
2494--- a/monitor_wrap.h 3019--- a/monitor_wrap.h
2495+++ b/monitor_wrap.h 3020+++ b/monitor_wrap.h
2496@@ -60,8 +60,10 @@ int mm_sshkey_verify(const struct sshkey *, const u_char *, size_t, 3021@@ -61,8 +61,10 @@ int mm_sshkey_verify(const struct sshkey *, const u_char *, size_t,
2497 OM_uint32 mm_ssh_gssapi_server_ctx(Gssctxt **, gss_OID); 3022 OM_uint32 mm_ssh_gssapi_server_ctx(Gssctxt **, gss_OID);
2498 OM_uint32 mm_ssh_gssapi_accept_ctx(Gssctxt *, 3023 OM_uint32 mm_ssh_gssapi_accept_ctx(Gssctxt *,
2499 gss_buffer_desc *, gss_buffer_desc *, OM_uint32 *); 3024 gss_buffer_desc *, gss_buffer_desc *, OM_uint32 *);
2500-int mm_ssh_gssapi_userok(char *user); 3025-int mm_ssh_gssapi_userok(char *user);
2501+int mm_ssh_gssapi_userok(char *user, struct passwd *); 3026+int mm_ssh_gssapi_userok(char *user, struct passwd *, int kex);
2502 OM_uint32 mm_ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t); 3027 OM_uint32 mm_ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t);
2503+OM_uint32 mm_ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t); 3028+OM_uint32 mm_ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t);
2504+int mm_ssh_gssapi_update_creds(ssh_gssapi_ccache *); 3029+int mm_ssh_gssapi_update_creds(ssh_gssapi_ccache *);
2505 #endif 3030 #endif
2506 3031
2507 #ifdef USE_PAM 3032 #ifdef USE_PAM
2508diff --git a/opacket.c b/opacket.c
2509index e637d7a71..7672c0b59 100644
2510--- a/opacket.c
2511+++ b/opacket.c
2512@@ -80,7 +80,7 @@ ssh_packet_put_raw(struct ssh *ssh, const void *buf, u_int len)
2513
2514 #ifdef WITH_OPENSSL
2515 void
2516-ssh_packet_put_bignum2(struct ssh *ssh, BIGNUM * value)
2517+ssh_packet_put_bignum2(struct ssh *ssh, const BIGNUM * value)
2518 {
2519 int r;
2520
2521diff --git a/opacket.h b/opacket.h
2522index f92fe586e..1cf66a2d3 100644
2523--- a/opacket.h
2524+++ b/opacket.h
2525@@ -7,7 +7,7 @@ void ssh_packet_start(struct ssh *, u_char);
2526 void ssh_packet_put_char(struct ssh *, int ch);
2527 void ssh_packet_put_int(struct ssh *, u_int value);
2528 void ssh_packet_put_int64(struct ssh *, u_int64_t value);
2529-void ssh_packet_put_bignum2(struct ssh *, BIGNUM * value);
2530+void ssh_packet_put_bignum2(struct ssh *, const BIGNUM * value);
2531 void ssh_packet_put_ecpoint(struct ssh *, const EC_GROUP *, const EC_POINT *);
2532 void ssh_packet_put_string(struct ssh *, const void *buf, u_int len);
2533 void ssh_packet_put_cstring(struct ssh *, const char *str);
2534diff --git a/readconf.c b/readconf.c 3033diff --git a/readconf.c b/readconf.c
2535index 433811521..36bc5e59a 100644 3034index ec497e79f..4d699e5f1 100644
2536--- a/readconf.c 3035--- a/readconf.c
2537+++ b/readconf.c 3036+++ b/readconf.c
2538@@ -161,6 +161,8 @@ typedef enum { 3037@@ -67,6 +67,7 @@
3038 #include "uidswap.h"
3039 #include "myproposal.h"
3040 #include "digest.h"
3041+#include "ssh-gss.h"
3042
3043 /* Format of the configuration file:
3044
3045@@ -162,6 +163,8 @@ typedef enum {
2539 oClearAllForwardings, oNoHostAuthenticationForLocalhost, 3046 oClearAllForwardings, oNoHostAuthenticationForLocalhost,
2540 oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout, 3047 oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
2541 oAddressFamily, oGssAuthentication, oGssDelegateCreds, 3048 oAddressFamily, oGssAuthentication, oGssDelegateCreds,
2542+ oGssTrustDns, oGssKeyEx, oGssClientIdentity, oGssRenewalRekey, 3049+ oGssTrustDns, oGssKeyEx, oGssClientIdentity, oGssRenewalRekey,
2543+ oGssServerIdentity, 3050+ oGssServerIdentity, oGssKexAlgorithms,
2544 oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly, 3051 oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
2545 oSendEnv, oSetEnv, oControlPath, oControlMaster, oControlPersist, 3052 oSendEnv, oSetEnv, oControlPath, oControlMaster, oControlPersist,
2546 oHashKnownHosts, 3053 oHashKnownHosts,
2547@@ -201,10 +203,20 @@ static struct { 3054@@ -202,10 +205,22 @@ static struct {
2548 /* Sometimes-unsupported options */ 3055 /* Sometimes-unsupported options */
2549 #if defined(GSSAPI) 3056 #if defined(GSSAPI)
2550 { "gssapiauthentication", oGssAuthentication }, 3057 { "gssapiauthentication", oGssAuthentication },
@@ -2554,6 +3061,7 @@ index 433811521..36bc5e59a 100644
2554+ { "gssapiclientidentity", oGssClientIdentity }, 3061+ { "gssapiclientidentity", oGssClientIdentity },
2555+ { "gssapiserveridentity", oGssServerIdentity }, 3062+ { "gssapiserveridentity", oGssServerIdentity },
2556+ { "gssapirenewalforcesrekey", oGssRenewalRekey }, 3063+ { "gssapirenewalforcesrekey", oGssRenewalRekey },
3064+ { "gssapikexalgorithms", oGssKexAlgorithms },
2557 # else 3065 # else
2558 { "gssapiauthentication", oUnsupported }, 3066 { "gssapiauthentication", oUnsupported },
2559+ { "gssapikeyexchange", oUnsupported }, 3067+ { "gssapikeyexchange", oUnsupported },
@@ -2562,10 +3070,11 @@ index 433811521..36bc5e59a 100644
2562+ { "gssapiclientidentity", oUnsupported }, 3070+ { "gssapiclientidentity", oUnsupported },
2563+ { "gssapiserveridentity", oUnsupported }, 3071+ { "gssapiserveridentity", oUnsupported },
2564+ { "gssapirenewalforcesrekey", oUnsupported }, 3072+ { "gssapirenewalforcesrekey", oUnsupported },
3073+ { "gssapikexalgorithms", oUnsupported },
2565 #endif 3074 #endif
2566 #ifdef ENABLE_PKCS11 3075 #ifdef ENABLE_PKCS11
2567 { "smartcarddevice", oPKCS11Provider }, 3076 { "pkcs11provider", oPKCS11Provider },
2568@@ -974,10 +986,30 @@ parse_time: 3077@@ -983,10 +998,42 @@ parse_time:
2569 intptr = &options->gss_authentication; 3078 intptr = &options->gss_authentication;
2570 goto parse_flag; 3079 goto parse_flag;
2571 3080
@@ -2593,10 +3102,22 @@ index 433811521..36bc5e59a 100644
2593+ intptr = &options->gss_renewal_rekey; 3102+ intptr = &options->gss_renewal_rekey;
2594+ goto parse_flag; 3103+ goto parse_flag;
2595+ 3104+
3105+ case oGssKexAlgorithms:
3106+ arg = strdelim(&s);
3107+ if (!arg || *arg == '\0')
3108+ fatal("%.200s line %d: Missing argument.",
3109+ filename, linenum);
3110+ if (!kex_gss_names_valid(arg))
3111+ fatal("%.200s line %d: Bad GSSAPI KexAlgorithms '%s'.",
3112+ filename, linenum, arg ? arg : "<NONE>");
3113+ if (*activep && options->gss_kex_algorithms == NULL)
3114+ options->gss_kex_algorithms = xstrdup(arg);
3115+ break;
3116+
2596 case oBatchMode: 3117 case oBatchMode:
2597 intptr = &options->batch_mode; 3118 intptr = &options->batch_mode;
2598 goto parse_flag; 3119 goto parse_flag;
2599@@ -1842,7 +1874,12 @@ initialize_options(Options * options) 3120@@ -1854,7 +1901,13 @@ initialize_options(Options * options)
2600 options->pubkey_authentication = -1; 3121 options->pubkey_authentication = -1;
2601 options->challenge_response_authentication = -1; 3122 options->challenge_response_authentication = -1;
2602 options->gss_authentication = -1; 3123 options->gss_authentication = -1;
@@ -2606,10 +3127,11 @@ index 433811521..36bc5e59a 100644
2606+ options->gss_renewal_rekey = -1; 3127+ options->gss_renewal_rekey = -1;
2607+ options->gss_client_identity = NULL; 3128+ options->gss_client_identity = NULL;
2608+ options->gss_server_identity = NULL; 3129+ options->gss_server_identity = NULL;
3130+ options->gss_kex_algorithms = NULL;
2609 options->password_authentication = -1; 3131 options->password_authentication = -1;
2610 options->kbd_interactive_authentication = -1; 3132 options->kbd_interactive_authentication = -1;
2611 options->kbd_interactive_devices = NULL; 3133 options->kbd_interactive_devices = NULL;
2612@@ -1988,8 +2025,14 @@ fill_default_options(Options * options) 3134@@ -2000,8 +2053,18 @@ fill_default_options(Options * options)
2613 options->challenge_response_authentication = 1; 3135 options->challenge_response_authentication = 1;
2614 if (options->gss_authentication == -1) 3136 if (options->gss_authentication == -1)
2615 options->gss_authentication = 0; 3137 options->gss_authentication = 0;
@@ -2621,14 +3143,33 @@ index 433811521..36bc5e59a 100644
2621+ options->gss_trust_dns = 0; 3143+ options->gss_trust_dns = 0;
2622+ if (options->gss_renewal_rekey == -1) 3144+ if (options->gss_renewal_rekey == -1)
2623+ options->gss_renewal_rekey = 0; 3145+ options->gss_renewal_rekey = 0;
3146+#ifdef GSSAPI
3147+ if (options->gss_kex_algorithms == NULL)
3148+ options->gss_kex_algorithms = strdup(GSS_KEX_DEFAULT_KEX);
3149+#endif
2624 if (options->password_authentication == -1) 3150 if (options->password_authentication == -1)
2625 options->password_authentication = 1; 3151 options->password_authentication = 1;
2626 if (options->kbd_interactive_authentication == -1) 3152 if (options->kbd_interactive_authentication == -1)
3153@@ -2616,7 +2679,14 @@ dump_client_config(Options *o, const char *host)
3154 dump_cfg_fmtint(oGatewayPorts, o->fwd_opts.gateway_ports);
3155 #ifdef GSSAPI
3156 dump_cfg_fmtint(oGssAuthentication, o->gss_authentication);
3157+ dump_cfg_fmtint(oGssKeyEx, o->gss_keyex);
3158 dump_cfg_fmtint(oGssDelegateCreds, o->gss_deleg_creds);
3159+ dump_cfg_fmtint(oGssTrustDns, o->gss_trust_dns);
3160+ dump_cfg_fmtint(oGssRenewalRekey, o->gss_renewal_rekey);
3161+ dump_cfg_string(oGssClientIdentity, o->gss_client_identity);
3162+ dump_cfg_string(oGssServerIdentity, o->gss_server_identity);
3163+ dump_cfg_string(oGssKexAlgorithms, o->gss_kex_algorithms ?
3164+ o->gss_kex_algorithms : GSS_KEX_DEFAULT_KEX);
3165 #endif /* GSSAPI */
3166 dump_cfg_fmtint(oHashKnownHosts, o->hash_known_hosts);
3167 dump_cfg_fmtint(oHostbasedAuthentication, o->hostbased_authentication);
2627diff --git a/readconf.h b/readconf.h 3168diff --git a/readconf.h b/readconf.h
2628index fc7e38251..8e4900d01 100644 3169index 8e36bf32a..0bff6d80a 100644
2629--- a/readconf.h 3170--- a/readconf.h
2630+++ b/readconf.h 3171+++ b/readconf.h
2631@@ -40,7 +40,12 @@ typedef struct { 3172@@ -40,7 +40,13 @@ typedef struct {
2632 int challenge_response_authentication; 3173 int challenge_response_authentication;
2633 /* Try S/Key or TIS, authentication. */ 3174 /* Try S/Key or TIS, authentication. */
2634 int gss_authentication; /* Try GSS authentication */ 3175 int gss_authentication; /* Try GSS authentication */
@@ -2638,14 +3179,23 @@ index fc7e38251..8e4900d01 100644
2638+ int gss_renewal_rekey; /* Credential renewal forces rekey */ 3179+ int gss_renewal_rekey; /* Credential renewal forces rekey */
2639+ char *gss_client_identity; /* Principal to initiate GSSAPI with */ 3180+ char *gss_client_identity; /* Principal to initiate GSSAPI with */
2640+ char *gss_server_identity; /* GSSAPI target principal */ 3181+ char *gss_server_identity; /* GSSAPI target principal */
3182+ char *gss_kex_algorithms; /* GSSAPI kex methods to be offered by client. */
2641 int password_authentication; /* Try password 3183 int password_authentication; /* Try password
2642 * authentication. */ 3184 * authentication. */
2643 int kbd_interactive_authentication; /* Try keyboard-interactive auth. */ 3185 int kbd_interactive_authentication; /* Try keyboard-interactive auth. */
2644diff --git a/servconf.c b/servconf.c 3186diff --git a/servconf.c b/servconf.c
2645index 932d363bb..4668b8a45 100644 3187index ffac5d2c7..ffdad31e7 100644
2646--- a/servconf.c 3188--- a/servconf.c
2647+++ b/servconf.c 3189+++ b/servconf.c
2648@@ -124,8 +124,10 @@ initialize_server_options(ServerOptions *options) 3190@@ -64,6 +64,7 @@
3191 #include "auth.h"
3192 #include "myproposal.h"
3193 #include "digest.h"
3194+#include "ssh-gss.h"
3195
3196 static void add_listen_addr(ServerOptions *, const char *,
3197 const char *, int);
3198@@ -124,8 +125,11 @@ initialize_server_options(ServerOptions *options)
2649 options->kerberos_ticket_cleanup = -1; 3199 options->kerberos_ticket_cleanup = -1;
2650 options->kerberos_get_afs_token = -1; 3200 options->kerberos_get_afs_token = -1;
2651 options->gss_authentication=-1; 3201 options->gss_authentication=-1;
@@ -2653,10 +3203,11 @@ index 932d363bb..4668b8a45 100644
2653 options->gss_cleanup_creds = -1; 3203 options->gss_cleanup_creds = -1;
2654 options->gss_strict_acceptor = -1; 3204 options->gss_strict_acceptor = -1;
2655+ options->gss_store_rekey = -1; 3205+ options->gss_store_rekey = -1;
3206+ options->gss_kex_algorithms = NULL;
2656 options->password_authentication = -1; 3207 options->password_authentication = -1;
2657 options->kbd_interactive_authentication = -1; 3208 options->kbd_interactive_authentication = -1;
2658 options->challenge_response_authentication = -1; 3209 options->challenge_response_authentication = -1;
2659@@ -337,10 +339,14 @@ fill_default_server_options(ServerOptions *options) 3210@@ -351,10 +355,18 @@ fill_default_server_options(ServerOptions *options)
2660 options->kerberos_get_afs_token = 0; 3211 options->kerberos_get_afs_token = 0;
2661 if (options->gss_authentication == -1) 3212 if (options->gss_authentication == -1)
2662 options->gss_authentication = 0; 3213 options->gss_authentication = 0;
@@ -2668,18 +3219,22 @@ index 932d363bb..4668b8a45 100644
2668 options->gss_strict_acceptor = 1; 3219 options->gss_strict_acceptor = 1;
2669+ if (options->gss_store_rekey == -1) 3220+ if (options->gss_store_rekey == -1)
2670+ options->gss_store_rekey = 0; 3221+ options->gss_store_rekey = 0;
3222+#ifdef GSSAPI
3223+ if (options->gss_kex_algorithms == NULL)
3224+ options->gss_kex_algorithms = strdup(GSS_KEX_DEFAULT_KEX);
3225+#endif
2671 if (options->password_authentication == -1) 3226 if (options->password_authentication == -1)
2672 options->password_authentication = 1; 3227 options->password_authentication = 1;
2673 if (options->kbd_interactive_authentication == -1) 3228 if (options->kbd_interactive_authentication == -1)
2674@@ -485,6 +491,7 @@ typedef enum { 3229@@ -498,6 +510,7 @@ typedef enum {
2675 sHostKeyAlgorithms, 3230 sHostKeyAlgorithms,
2676 sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile, 3231 sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile,
2677 sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor, 3232 sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor,
2678+ sGssKeyEx, sGssStoreRekey, 3233+ sGssKeyEx, sGssKexAlgorithms, sGssStoreRekey,
2679 sAcceptEnv, sSetEnv, sPermitTunnel, 3234 sAcceptEnv, sSetEnv, sPermitTunnel,
2680 sMatch, sPermitOpen, sPermitListen, sForceCommand, sChrootDirectory, 3235 sMatch, sPermitOpen, sPermitListen, sForceCommand, sChrootDirectory,
2681 sUsePrivilegeSeparation, sAllowAgentForwarding, 3236 sUsePrivilegeSeparation, sAllowAgentForwarding,
2682@@ -559,12 +566,20 @@ static struct { 3237@@ -572,12 +585,22 @@ static struct {
2683 #ifdef GSSAPI 3238 #ifdef GSSAPI
2684 { "gssapiauthentication", sGssAuthentication, SSHCFG_ALL }, 3239 { "gssapiauthentication", sGssAuthentication, SSHCFG_ALL },
2685 { "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL }, 3240 { "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL },
@@ -2687,6 +3242,7 @@ index 932d363bb..4668b8a45 100644
2687 { "gssapistrictacceptorcheck", sGssStrictAcceptor, SSHCFG_GLOBAL }, 3242 { "gssapistrictacceptorcheck", sGssStrictAcceptor, SSHCFG_GLOBAL },
2688+ { "gssapikeyexchange", sGssKeyEx, SSHCFG_GLOBAL }, 3243+ { "gssapikeyexchange", sGssKeyEx, SSHCFG_GLOBAL },
2689+ { "gssapistorecredentialsonrekey", sGssStoreRekey, SSHCFG_GLOBAL }, 3244+ { "gssapistorecredentialsonrekey", sGssStoreRekey, SSHCFG_GLOBAL },
3245+ { "gssapikexalgorithms", sGssKexAlgorithms, SSHCFG_GLOBAL },
2690 #else 3246 #else
2691 { "gssapiauthentication", sUnsupported, SSHCFG_ALL }, 3247 { "gssapiauthentication", sUnsupported, SSHCFG_ALL },
2692 { "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL }, 3248 { "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL },
@@ -2694,13 +3250,14 @@ index 932d363bb..4668b8a45 100644
2694 { "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL }, 3250 { "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL },
2695+ { "gssapikeyexchange", sUnsupported, SSHCFG_GLOBAL }, 3251+ { "gssapikeyexchange", sUnsupported, SSHCFG_GLOBAL },
2696+ { "gssapistorecredentialsonrekey", sUnsupported, SSHCFG_GLOBAL }, 3252+ { "gssapistorecredentialsonrekey", sUnsupported, SSHCFG_GLOBAL },
3253+ { "gssapikexalgorithms", sUnsupported, SSHCFG_GLOBAL },
2697 #endif 3254 #endif
2698+ { "gssusesessionccache", sUnsupported, SSHCFG_GLOBAL }, 3255+ { "gssusesessionccache", sUnsupported, SSHCFG_GLOBAL },
2699+ { "gssapiusesessioncredcache", sUnsupported, SSHCFG_GLOBAL }, 3256+ { "gssapiusesessioncredcache", sUnsupported, SSHCFG_GLOBAL },
2700 { "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL }, 3257 { "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL },
2701 { "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL }, 3258 { "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL },
2702 { "challengeresponseauthentication", sChallengeResponseAuthentication, SSHCFG_GLOBAL }, 3259 { "challengeresponseauthentication", sChallengeResponseAuthentication, SSHCFG_GLOBAL },
2703@@ -1468,6 +1483,10 @@ process_server_config_line(ServerOptions *options, char *line, 3260@@ -1485,6 +1508,10 @@ process_server_config_line(ServerOptions *options, char *line,
2704 intptr = &options->gss_authentication; 3261 intptr = &options->gss_authentication;
2705 goto parse_flag; 3262 goto parse_flag;
2706 3263
@@ -2711,7 +3268,7 @@ index 932d363bb..4668b8a45 100644
2711 case sGssCleanupCreds: 3268 case sGssCleanupCreds:
2712 intptr = &options->gss_cleanup_creds; 3269 intptr = &options->gss_cleanup_creds;
2713 goto parse_flag; 3270 goto parse_flag;
2714@@ -1476,6 +1495,10 @@ process_server_config_line(ServerOptions *options, char *line, 3271@@ -1493,6 +1520,22 @@ process_server_config_line(ServerOptions *options, char *line,
2715 intptr = &options->gss_strict_acceptor; 3272 intptr = &options->gss_strict_acceptor;
2716 goto parse_flag; 3273 goto parse_flag;
2717 3274
@@ -2719,25 +3276,37 @@ index 932d363bb..4668b8a45 100644
2719+ intptr = &options->gss_store_rekey; 3276+ intptr = &options->gss_store_rekey;
2720+ goto parse_flag; 3277+ goto parse_flag;
2721+ 3278+
3279+ case sGssKexAlgorithms:
3280+ arg = strdelim(&cp);
3281+ if (!arg || *arg == '\0')
3282+ fatal("%.200s line %d: Missing argument.",
3283+ filename, linenum);
3284+ if (!kex_gss_names_valid(arg))
3285+ fatal("%.200s line %d: Bad GSSAPI KexAlgorithms '%s'.",
3286+ filename, linenum, arg ? arg : "<NONE>");
3287+ if (*activep && options->gss_kex_algorithms == NULL)
3288+ options->gss_kex_algorithms = xstrdup(arg);
3289+ break;
3290+
2722 case sPasswordAuthentication: 3291 case sPasswordAuthentication:
2723 intptr = &options->password_authentication; 3292 intptr = &options->password_authentication;
2724 goto parse_flag; 3293 goto parse_flag;
2725@@ -2560,7 +2583,10 @@ dump_config(ServerOptions *o) 3294@@ -2579,6 +2622,10 @@ dump_config(ServerOptions *o)
2726 #endif
2727 #ifdef GSSAPI 3295 #ifdef GSSAPI
2728 dump_cfg_fmtint(sGssAuthentication, o->gss_authentication); 3296 dump_cfg_fmtint(sGssAuthentication, o->gss_authentication);
2729+ dump_cfg_fmtint(sGssKeyEx, o->gss_keyex);
2730 dump_cfg_fmtint(sGssCleanupCreds, o->gss_cleanup_creds); 3297 dump_cfg_fmtint(sGssCleanupCreds, o->gss_cleanup_creds);
3298+ dump_cfg_fmtint(sGssKeyEx, o->gss_keyex);
2731+ dump_cfg_fmtint(sGssStrictAcceptor, o->gss_strict_acceptor); 3299+ dump_cfg_fmtint(sGssStrictAcceptor, o->gss_strict_acceptor);
2732+ dump_cfg_fmtint(sGssStoreRekey, o->gss_store_rekey); 3300+ dump_cfg_fmtint(sGssStoreRekey, o->gss_store_rekey);
3301+ dump_cfg_string(sGssKexAlgorithms, o->gss_kex_algorithms);
2733 #endif 3302 #endif
2734 dump_cfg_fmtint(sPasswordAuthentication, o->password_authentication); 3303 dump_cfg_fmtint(sPasswordAuthentication, o->password_authentication);
2735 dump_cfg_fmtint(sKbdInteractiveAuthentication, 3304 dump_cfg_fmtint(sKbdInteractiveAuthentication,
2736diff --git a/servconf.h b/servconf.h 3305diff --git a/servconf.h b/servconf.h
2737index 0175e00e8..3b76da816 100644 3306index 54e0a8d8d..a476d5220 100644
2738--- a/servconf.h 3307--- a/servconf.h
2739+++ b/servconf.h 3308+++ b/servconf.h
2740@@ -125,8 +125,10 @@ typedef struct { 3309@@ -126,8 +126,11 @@ typedef struct {
2741 int kerberos_get_afs_token; /* If true, try to get AFS token if 3310 int kerberos_get_afs_token; /* If true, try to get AFS token if
2742 * authenticated with Kerberos. */ 3311 * authenticated with Kerberos. */
2743 int gss_authentication; /* If true, permit GSSAPI authentication */ 3312 int gss_authentication; /* If true, permit GSSAPI authentication */
@@ -2745,11 +3314,38 @@ index 0175e00e8..3b76da816 100644
2745 int gss_cleanup_creds; /* If true, destroy cred cache on logout */ 3314 int gss_cleanup_creds; /* If true, destroy cred cache on logout */
2746 int gss_strict_acceptor; /* If true, restrict the GSSAPI acceptor name */ 3315 int gss_strict_acceptor; /* If true, restrict the GSSAPI acceptor name */
2747+ int gss_store_rekey; 3316+ int gss_store_rekey;
3317+ char *gss_kex_algorithms; /* GSSAPI kex methods to be offered by client. */
2748 int password_authentication; /* If true, permit password 3318 int password_authentication; /* If true, permit password
2749 * authentication. */ 3319 * authentication. */
2750 int kbd_interactive_authentication; /* If true, permit */ 3320 int kbd_interactive_authentication; /* If true, permit */
3321diff --git a/session.c b/session.c
3322index ac06b08e9..ac3d9d19d 100644
3323--- a/session.c
3324+++ b/session.c
3325@@ -2674,13 +2674,19 @@ do_cleanup(struct ssh *ssh, Authctxt *authctxt)
3326
3327 #ifdef KRB5
3328 if (options.kerberos_ticket_cleanup &&
3329- authctxt->krb5_ctx)
3330+ authctxt->krb5_ctx) {
3331+ temporarily_use_uid(authctxt->pw);
3332 krb5_cleanup_proc(authctxt);
3333+ restore_uid();
3334+ }
3335 #endif
3336
3337 #ifdef GSSAPI
3338- if (options.gss_cleanup_creds)
3339+ if (options.gss_cleanup_creds) {
3340+ temporarily_use_uid(authctxt->pw);
3341 ssh_gssapi_cleanup_creds();
3342+ restore_uid();
3343+ }
3344 #endif
3345
3346 /* remove agent socket */
2751diff --git a/ssh-gss.h b/ssh-gss.h 3347diff --git a/ssh-gss.h b/ssh-gss.h
2752index 36180d07a..350ce7882 100644 3348index 36180d07a..70dd36658 100644
2753--- a/ssh-gss.h 3349--- a/ssh-gss.h
2754+++ b/ssh-gss.h 3350+++ b/ssh-gss.h
2755@@ -1,6 +1,6 @@ 3351@@ -1,6 +1,6 @@
@@ -2760,7 +3356,7 @@ index 36180d07a..350ce7882 100644
2760 * 3356 *
2761 * Redistribution and use in source and binary forms, with or without 3357 * Redistribution and use in source and binary forms, with or without
2762 * modification, are permitted provided that the following conditions 3358 * modification, are permitted provided that the following conditions
2763@@ -61,10 +61,22 @@ 3359@@ -61,10 +61,30 @@
2764 3360
2765 #define SSH_GSS_OIDTYPE 0x06 3361 #define SSH_GSS_OIDTYPE 0x06
2766 3362
@@ -2773,7 +3369,15 @@ index 36180d07a..350ce7882 100644
2773+#define SSH2_MSG_KEXGSS_GROUP 41 3369+#define SSH2_MSG_KEXGSS_GROUP 41
2774+#define KEX_GSS_GRP1_SHA1_ID "gss-group1-sha1-" 3370+#define KEX_GSS_GRP1_SHA1_ID "gss-group1-sha1-"
2775+#define KEX_GSS_GRP14_SHA1_ID "gss-group14-sha1-" 3371+#define KEX_GSS_GRP14_SHA1_ID "gss-group14-sha1-"
3372+#define KEX_GSS_GRP14_SHA256_ID "gss-group14-sha256-"
3373+#define KEX_GSS_GRP16_SHA512_ID "gss-group16-sha512-"
2776+#define KEX_GSS_GEX_SHA1_ID "gss-gex-sha1-" 3374+#define KEX_GSS_GEX_SHA1_ID "gss-gex-sha1-"
3375+#define KEX_GSS_NISTP256_SHA256_ID "gss-nistp256-sha256-"
3376+#define KEX_GSS_C25519_SHA256_ID "gss-curve25519-sha256-"
3377+
3378+#define GSS_KEX_DEFAULT_KEX \
3379+ KEX_GSS_GEX_SHA1_ID "," \
3380+ KEX_GSS_GRP14_SHA1_ID
2777+ 3381+
2778 typedef struct { 3382 typedef struct {
2779 char *filename; 3383 char *filename;
@@ -2783,7 +3387,7 @@ index 36180d07a..350ce7882 100644
2783 void *data; 3387 void *data;
2784 } ssh_gssapi_ccache; 3388 } ssh_gssapi_ccache;
2785 3389
2786@@ -72,8 +84,11 @@ typedef struct { 3390@@ -72,8 +92,11 @@ typedef struct {
2787 gss_buffer_desc displayname; 3391 gss_buffer_desc displayname;
2788 gss_buffer_desc exportedname; 3392 gss_buffer_desc exportedname;
2789 gss_cred_id_t creds; 3393 gss_cred_id_t creds;
@@ -2795,7 +3399,7 @@ index 36180d07a..350ce7882 100644
2795 } ssh_gssapi_client; 3399 } ssh_gssapi_client;
2796 3400
2797 typedef struct ssh_gssapi_mech_struct { 3401 typedef struct ssh_gssapi_mech_struct {
2798@@ -84,6 +99,7 @@ typedef struct ssh_gssapi_mech_struct { 3402@@ -84,6 +107,7 @@ typedef struct ssh_gssapi_mech_struct {
2799 int (*userok) (ssh_gssapi_client *, char *); 3403 int (*userok) (ssh_gssapi_client *, char *);
2800 int (*localname) (ssh_gssapi_client *, char **); 3404 int (*localname) (ssh_gssapi_client *, char **);
2801 void (*storecreds) (ssh_gssapi_client *); 3405 void (*storecreds) (ssh_gssapi_client *);
@@ -2803,7 +3407,7 @@ index 36180d07a..350ce7882 100644
2803 } ssh_gssapi_mech; 3407 } ssh_gssapi_mech;
2804 3408
2805 typedef struct { 3409 typedef struct {
2806@@ -94,10 +110,11 @@ typedef struct { 3410@@ -94,10 +118,11 @@ typedef struct {
2807 gss_OID oid; /* client */ 3411 gss_OID oid; /* client */
2808 gss_cred_id_t creds; /* server */ 3412 gss_cred_id_t creds; /* server */
2809 gss_name_t client; /* server */ 3413 gss_name_t client; /* server */
@@ -2816,7 +3420,15 @@ index 36180d07a..350ce7882 100644
2816 3420
2817 int ssh_gssapi_check_oid(Gssctxt *, void *, size_t); 3421 int ssh_gssapi_check_oid(Gssctxt *, void *, size_t);
2818 void ssh_gssapi_set_oid_data(Gssctxt *, void *, size_t); 3422 void ssh_gssapi_set_oid_data(Gssctxt *, void *, size_t);
2819@@ -123,17 +140,33 @@ void ssh_gssapi_delete_ctx(Gssctxt **); 3423@@ -109,6 +134,7 @@ OM_uint32 ssh_gssapi_test_oid_supported(OM_uint32 *, gss_OID, int *);
3424
3425 struct sshbuf;
3426 int ssh_gssapi_get_buffer_desc(struct sshbuf *, gss_buffer_desc *);
3427+int ssh_gssapi_sshpkt_get_buffer_desc(struct ssh *, gss_buffer_desc *);
3428
3429 OM_uint32 ssh_gssapi_import_name(Gssctxt *, const char *);
3430 OM_uint32 ssh_gssapi_init_ctx(Gssctxt *, int,
3431@@ -123,17 +149,33 @@ void ssh_gssapi_delete_ctx(Gssctxt **);
2820 OM_uint32 ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t); 3432 OM_uint32 ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t);
2821 void ssh_gssapi_buildmic(struct sshbuf *, const char *, 3433 void ssh_gssapi_buildmic(struct sshbuf *, const char *,
2822 const char *, const char *); 3434 const char *, const char *);
@@ -2826,17 +3438,17 @@ index 36180d07a..350ce7882 100644
2826+int ssh_gssapi_credentials_updated(Gssctxt *); 3438+int ssh_gssapi_credentials_updated(Gssctxt *);
2827 3439
2828 /* In the server */ 3440 /* In the server */
2829+typedef int ssh_gssapi_check_fn(Gssctxt **, gss_OID, const char *, 3441+typedef int ssh_gssapi_check_fn(Gssctxt **, gss_OID, const char *,
2830+ const char *); 3442+ const char *);
2831+char *ssh_gssapi_client_mechanisms(const char *, const char *); 3443+char *ssh_gssapi_client_mechanisms(const char *, const char *, const char *);
2832+char *ssh_gssapi_kex_mechs(gss_OID_set, ssh_gssapi_check_fn *, const char *, 3444+char *ssh_gssapi_kex_mechs(gss_OID_set, ssh_gssapi_check_fn *, const char *,
2833+ const char *); 3445+ const char *, const char *);
2834+gss_OID ssh_gssapi_id_kex(Gssctxt *, char *, int); 3446+gss_OID ssh_gssapi_id_kex(Gssctxt *, char *, int);
2835+int ssh_gssapi_server_check_mech(Gssctxt **,gss_OID, const char *, 3447+int ssh_gssapi_server_check_mech(Gssctxt **,gss_OID, const char *,
2836+ const char *); 3448+ const char *);
2837 OM_uint32 ssh_gssapi_server_ctx(Gssctxt **, gss_OID); 3449 OM_uint32 ssh_gssapi_server_ctx(Gssctxt **, gss_OID);
2838-int ssh_gssapi_userok(char *name); 3450-int ssh_gssapi_userok(char *name);
2839+int ssh_gssapi_userok(char *name, struct passwd *); 3451+int ssh_gssapi_userok(char *name, struct passwd *, int kex);
2840 OM_uint32 ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t); 3452 OM_uint32 ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t);
2841 void ssh_gssapi_do_child(char ***, u_int *); 3453 void ssh_gssapi_do_child(char ***, u_int *);
2842 void ssh_gssapi_cleanup_creds(void); 3454 void ssh_gssapi_cleanup_creds(void);
@@ -2852,8 +3464,57 @@ index 36180d07a..350ce7882 100644
2852 #endif /* GSSAPI */ 3464 #endif /* GSSAPI */
2853 3465
2854 #endif /* _SSH_GSS_H */ 3466 #endif /* _SSH_GSS_H */
3467diff --git a/ssh.1 b/ssh.1
3468index 9480eba8d..a1c7d2305 100644
3469--- a/ssh.1
3470+++ b/ssh.1
3471@@ -497,7 +497,13 @@ For full details of the options listed below, and their possible values, see
3472 .It GatewayPorts
3473 .It GlobalKnownHostsFile
3474 .It GSSAPIAuthentication
3475+.It GSSAPIKeyExchange
3476+.It GSSAPIClientIdentity
3477 .It GSSAPIDelegateCredentials
3478+.It GSSAPIKexAlgorithms
3479+.It GSSAPIRenewalForcesRekey
3480+.It GSSAPIServerIdentity
3481+.It GSSAPITrustDns
3482 .It HashKnownHosts
3483 .It Host
3484 .It HostbasedAuthentication
3485@@ -573,6 +579,8 @@ flag),
3486 (supported message integrity codes),
3487 .Ar kex
3488 (key exchange algorithms),
3489+.Ar kex-gss
3490+(GSSAPI key exchange algorithms),
3491 .Ar key
3492 (key types),
3493 .Ar key-cert
3494diff --git a/ssh.c b/ssh.c
3495index 91e7c3511..42be7d88f 100644
3496--- a/ssh.c
3497+++ b/ssh.c
3498@@ -736,6 +736,8 @@ main(int ac, char **av)
3499 cp = mac_alg_list('\n');
3500 else if (strcmp(optarg, "kex") == 0)
3501 cp = kex_alg_list('\n');
3502+ else if (strcmp(optarg, "kex-gss") == 0)
3503+ cp = kex_gss_alg_list('\n');
3504 else if (strcmp(optarg, "key") == 0)
3505 cp = sshkey_alg_list(0, 0, 0, '\n');
3506 else if (strcmp(optarg, "key-cert") == 0)
3507@@ -748,7 +750,7 @@ main(int ac, char **av)
3508 cp = xstrdup("2");
3509 else if (strcmp(optarg, "help") == 0) {
3510 cp = xstrdup(
3511- "cipher\ncipher-auth\nkex\nkey\n"
3512+ "cipher\ncipher-auth\nkex\nkex-gss\nkey\n"
3513 "key-cert\nkey-plain\nmac\n"
3514 "protocol-version\nsig");
3515 }
2855diff --git a/ssh_config b/ssh_config 3516diff --git a/ssh_config b/ssh_config
2856index c12f5ef52..bcb9f153d 100644 3517index 5e8ef548b..1ff999b68 100644
2857--- a/ssh_config 3518--- a/ssh_config
2858+++ b/ssh_config 3519+++ b/ssh_config
2859@@ -24,6 +24,8 @@ 3520@@ -24,6 +24,8 @@
@@ -2866,61 +3527,95 @@ index c12f5ef52..bcb9f153d 100644
2866 # CheckHostIP yes 3527 # CheckHostIP yes
2867 # AddressFamily any 3528 # AddressFamily any
2868diff --git a/ssh_config.5 b/ssh_config.5 3529diff --git a/ssh_config.5 b/ssh_config.5
2869index 4d5b01d3e..16c79368a 100644 3530index 412629637..c3c8b274a 100644
2870--- a/ssh_config.5 3531--- a/ssh_config.5
2871+++ b/ssh_config.5 3532+++ b/ssh_config.5
2872@@ -736,10 +736,42 @@ The default is 3533@@ -754,10 +754,67 @@ The default is
2873 Specifies whether user authentication based on GSSAPI is allowed. 3534 Specifies whether user authentication based on GSSAPI is allowed.
2874 The default is 3535 The default is
2875 .Cm no . 3536 .Cm no .
2876+.It Cm GSSAPIKeyExchange
2877+Specifies whether key exchange based on GSSAPI may be used. When using
2878+GSSAPI key exchange the server need not have a host key.
2879+The default is
2880+.Cm no .
2881+.It Cm GSSAPIClientIdentity 3537+.It Cm GSSAPIClientIdentity
2882+If set, specifies the GSSAPI client identity that ssh should use when 3538+If set, specifies the GSSAPI client identity that ssh should use when
2883+connecting to the server. The default is unset, which means that the default 3539+connecting to the server. The default is unset, which means that the default
2884+identity will be used. 3540+identity will be used.
2885+.It Cm GSSAPIServerIdentity
2886+If set, specifies the GSSAPI server identity that ssh should expect when
2887+connecting to the server. The default is unset, which means that the
2888+expected GSSAPI server identity will be determined from the target
2889+hostname.
2890 .It Cm GSSAPIDelegateCredentials 3541 .It Cm GSSAPIDelegateCredentials
2891 Forward (delegate) credentials to the server. 3542 Forward (delegate) credentials to the server.
2892 The default is 3543 The default is
2893 .Cm no . 3544 .Cm no .
3545+.It Cm GSSAPIKeyExchange
3546+Specifies whether key exchange based on GSSAPI may be used. When using
3547+GSSAPI key exchange the server need not have a host key.
3548+The default is
3549+.Dq no .
2894+.It Cm GSSAPIRenewalForcesRekey 3550+.It Cm GSSAPIRenewalForcesRekey
2895+If set to 3551+If set to
2896+.Cm yes 3552+.Dq yes
2897+then renewal of the client's GSSAPI credentials will force the rekeying of the 3553+then renewal of the client's GSSAPI credentials will force the rekeying of the
2898+ssh connection. With a compatible server, this can delegate the renewed 3554+ssh connection. With a compatible server, this will delegate the renewed
2899+credentials to a session on the server. 3555+credentials to a session on the server.
3556+.Pp
3557+Checks are made to ensure that credentials are only propagated when the new
3558+credentials match the old ones on the originating client and where the
3559+receiving server still has the old set in its cache.
3560+.Pp
2900+The default is 3561+The default is
2901+.Cm no . 3562+.Dq no .
3563+.Pp
3564+For this to work
3565+.Cm GSSAPIKeyExchange
3566+needs to be enabled in the server and also used by the client.
3567+.It Cm GSSAPIServerIdentity
3568+If set, specifies the GSSAPI server identity that ssh should expect when
3569+connecting to the server. The default is unset, which means that the
3570+expected GSSAPI server identity will be determined from the target
3571+hostname.
2902+.It Cm GSSAPITrustDns 3572+.It Cm GSSAPITrustDns
2903+Set to 3573+Set to
2904+.Cm yes 3574+.Dq yes
2905+to indicate that the DNS is trusted to securely canonicalize 3575+to indicate that the DNS is trusted to securely canonicalize
2906+the name of the host being connected to. If 3576+the name of the host being connected to. If
2907+.Cm no , 3577+.Dq no ,
2908+the hostname entered on the 3578+the hostname entered on the
2909+command line will be passed untouched to the GSSAPI library. 3579+command line will be passed untouched to the GSSAPI library.
2910+The default is 3580+The default is
2911+.Cm no . 3581+.Dq no .
3582+.It Cm GSSAPIKexAlgorithms
3583+The list of key exchange algorithms that are offered for GSSAPI
3584+key exchange. Possible values are
3585+.Bd -literal -offset 3n
3586+gss-gex-sha1-,
3587+gss-group1-sha1-,
3588+gss-group14-sha1-,
3589+gss-group14-sha256-,
3590+gss-group16-sha512-,
3591+gss-nistp256-sha256-,
3592+gss-curve25519-sha256-
3593+.Ed
3594+.Pp
3595+The default is
3596+.Dq gss-gex-sha1-,gss-group14-sha1- .
3597+This option only applies to protocol version 2 connections using GSSAPI.
2912 .It Cm HashKnownHosts 3598 .It Cm HashKnownHosts
2913 Indicates that 3599 Indicates that
2914 .Xr ssh 1 3600 .Xr ssh 1
2915diff --git a/sshconnect2.c b/sshconnect2.c 3601diff --git a/sshconnect2.c b/sshconnect2.c
2916index 1675f3935..8c872a4fb 100644 3602index dffee90b1..4020371ae 100644
2917--- a/sshconnect2.c 3603--- a/sshconnect2.c
2918+++ b/sshconnect2.c 3604+++ b/sshconnect2.c
2919@@ -162,6 +162,11 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port) 3605@@ -78,8 +78,6 @@
2920 struct kex *kex; 3606 #endif
3607
3608 /* import */
3609-extern char *client_version_string;
3610-extern char *server_version_string;
3611 extern Options options;
3612
3613 /*
3614@@ -161,6 +159,11 @@ ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port)
3615 char *s, *all_key;
2921 int r; 3616 int r;
2922 3617
2923+#ifdef GSSAPI 3618+#if defined(GSSAPI) && defined(WITH_OPENSSL)
2924+ char *orig = NULL, *gss = NULL; 3619+ char *orig = NULL, *gss = NULL;
2925+ char *gss_host = NULL; 3620+ char *gss_host = NULL;
2926+#endif 3621+#endif
@@ -2928,11 +3623,11 @@ index 1675f3935..8c872a4fb 100644
2928 xxx_host = host; 3623 xxx_host = host;
2929 xxx_hostaddr = hostaddr; 3624 xxx_hostaddr = hostaddr;
2930 3625
2931@@ -194,6 +199,35 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port) 3626@@ -193,6 +196,35 @@ ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port)
2932 order_hostkeyalgs(host, hostaddr, port)); 3627 order_hostkeyalgs(host, hostaddr, port));
2933 } 3628 }
2934 3629
2935+#ifdef GSSAPI 3630+#if defined(GSSAPI) && defined(WITH_OPENSSL)
2936+ if (options.gss_keyex) { 3631+ if (options.gss_keyex) {
2937+ /* Add the GSSAPI mechanisms currently supported on this 3632+ /* Add the GSSAPI mechanisms currently supported on this
2938+ * client to the key exchange algorithm proposal */ 3633+ * client to the key exchange algorithm proposal */
@@ -2941,19 +3636,19 @@ index 1675f3935..8c872a4fb 100644
2941+ if (options.gss_server_identity) 3636+ if (options.gss_server_identity)
2942+ gss_host = xstrdup(options.gss_server_identity); 3637+ gss_host = xstrdup(options.gss_server_identity);
2943+ else if (options.gss_trust_dns) 3638+ else if (options.gss_trust_dns)
2944+ gss_host = remote_hostname(active_state); 3639+ gss_host = remote_hostname(ssh);
2945+ else 3640+ else
2946+ gss_host = xstrdup(host); 3641+ gss_host = xstrdup(host);
2947+ 3642+
2948+ gss = ssh_gssapi_client_mechanisms(gss_host, 3643+ gss = ssh_gssapi_client_mechanisms(gss_host,
2949+ options.gss_client_identity); 3644+ options.gss_client_identity, options.gss_kex_algorithms);
2950+ if (gss) { 3645+ if (gss) {
2951+ debug("Offering GSSAPI proposal: %s", gss); 3646+ debug("Offering GSSAPI proposal: %s", gss);
2952+ xasprintf(&myproposal[PROPOSAL_KEX_ALGS], 3647+ xasprintf(&myproposal[PROPOSAL_KEX_ALGS],
2953+ "%s,%s", gss, orig); 3648+ "%s,%s", gss, orig);
2954+ 3649+
2955+ /* If we've got GSSAPI algorithms, then we also 3650+ /* If we've got GSSAPI algorithms, then we also support the
2956+ * support the 'null' hostkey, as a last resort */ 3651+ * 'null' hostkey, as a last resort */
2957+ orig = myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]; 3652+ orig = myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS];
2958+ xasprintf(&myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS], 3653+ xasprintf(&myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS],
2959+ "%s,null", orig); 3654+ "%s,null", orig);
@@ -2962,38 +3657,43 @@ index 1675f3935..8c872a4fb 100644
2962+#endif 3657+#endif
2963+ 3658+
2964 if (options.rekey_limit || options.rekey_interval) 3659 if (options.rekey_limit || options.rekey_interval)
2965 packet_set_rekey_limits(options.rekey_limit, 3660 ssh_packet_set_rekey_limits(ssh, options.rekey_limit,
2966 options.rekey_interval); 3661 options.rekey_interval);
2967@@ -215,15 +249,41 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port) 3662@@ -211,16 +243,46 @@ ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port)
3663 # ifdef OPENSSL_HAS_ECC
3664 ssh->kex->kex[KEX_ECDH_SHA2] = kex_gen_client;
2968 # endif 3665 # endif
2969 #endif 3666+# ifdef GSSAPI
2970 kex->kex[KEX_C25519_SHA256] = kexc25519_client;
2971+#ifdef GSSAPI
2972+ if (options.gss_keyex) { 3667+ if (options.gss_keyex) {
2973+ kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_client; 3668+ ssh->kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_client;
2974+ kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_client; 3669+ ssh->kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_client;
2975+ kex->kex[KEX_GSS_GEX_SHA1] = kexgss_client; 3670+ ssh->kex->kex[KEX_GSS_GRP14_SHA256] = kexgss_client;
3671+ ssh->kex->kex[KEX_GSS_GRP16_SHA512] = kexgss_client;
3672+ ssh->kex->kex[KEX_GSS_GEX_SHA1] = kexgssgex_client;
3673+ ssh->kex->kex[KEX_GSS_NISTP256_SHA256] = kexgss_client;
3674+ ssh->kex->kex[KEX_GSS_C25519_SHA256] = kexgss_client;
2976+ } 3675+ }
2977+#endif 3676+# endif
2978 kex->client_version_string=client_version_string; 3677 #endif
2979 kex->server_version_string=server_version_string; 3678 ssh->kex->kex[KEX_C25519_SHA256] = kex_gen_client;
2980 kex->verify_host_key=&verify_host_key_callback; 3679 ssh->kex->kex[KEX_KEM_SNTRUP4591761X25519_SHA512] = kex_gen_client;
3680 ssh->kex->verify_host_key=&verify_host_key_callback;
2981 3681
2982+#ifdef GSSAPI 3682+#if defined(GSSAPI) && defined(WITH_OPENSSL)
2983+ if (options.gss_keyex) { 3683+ if (options.gss_keyex) {
2984+ kex->gss_deleg_creds = options.gss_deleg_creds; 3684+ ssh->kex->gss_deleg_creds = options.gss_deleg_creds;
2985+ kex->gss_trust_dns = options.gss_trust_dns; 3685+ ssh->kex->gss_trust_dns = options.gss_trust_dns;
2986+ kex->gss_client = options.gss_client_identity; 3686+ ssh->kex->gss_client = options.gss_client_identity;
2987+ kex->gss_host = gss_host; 3687+ ssh->kex->gss_host = gss_host;
2988+ } 3688+ }
2989+#endif 3689+#endif
2990+ 3690+
2991 ssh_dispatch_run_fatal(active_state, DISPATCH_BLOCK, &kex->done); 3691 ssh_dispatch_run_fatal(ssh, DISPATCH_BLOCK, &ssh->kex->done);
2992 3692
2993 /* remove ext-info from the KEX proposals for rekeying */ 3693 /* remove ext-info from the KEX proposals for rekeying */
2994 myproposal[PROPOSAL_KEX_ALGS] = 3694 myproposal[PROPOSAL_KEX_ALGS] =
2995 compat_kex_proposal(options.kex_algorithms); 3695 compat_kex_proposal(options.kex_algorithms);
2996+#ifdef GSSAPI 3696+#if defined(GSSAPI) && defined(WITH_OPENSSL)
2997+ /* repair myproposal after it was crumpled by the */ 3697+ /* repair myproposal after it was crumpled by the */
2998+ /* ext-info removal above */ 3698+ /* ext-info removal above */
2999+ if (gss) { 3699+ if (gss) {
@@ -3003,82 +3703,83 @@ index 1675f3935..8c872a4fb 100644
3003+ free(gss); 3703+ free(gss);
3004+ } 3704+ }
3005+#endif 3705+#endif
3006 if ((r = kex_prop2buf(kex->my, myproposal)) != 0) 3706 if ((r = kex_prop2buf(ssh->kex->my, myproposal)) != 0)
3007 fatal("kex_prop2buf: %s", ssh_err(r)); 3707 fatal("kex_prop2buf: %s", ssh_err(r));
3008 3708
3009@@ -314,6 +374,7 @@ int input_gssapi_token(int type, u_int32_t, struct ssh *); 3709@@ -317,6 +379,7 @@ static int input_gssapi_response(int type, u_int32_t, struct ssh *);
3010 int input_gssapi_hash(int type, u_int32_t, struct ssh *); 3710 static int input_gssapi_token(int type, u_int32_t, struct ssh *);
3011 int input_gssapi_error(int, u_int32_t, struct ssh *); 3711 static int input_gssapi_error(int, u_int32_t, struct ssh *);
3012 int input_gssapi_errtok(int, u_int32_t, struct ssh *); 3712 static int input_gssapi_errtok(int, u_int32_t, struct ssh *);
3013+int userauth_gsskeyex(Authctxt *authctxt); 3713+static int userauth_gsskeyex(struct ssh *);
3014 #endif 3714 #endif
3015 3715
3016 void userauth(Authctxt *, char *); 3716 void userauth(struct ssh *, char *);
3017@@ -330,6 +391,11 @@ static char *authmethods_get(void); 3717@@ -333,6 +396,11 @@ static char *authmethods_get(void);
3018 3718
3019 Authmethod authmethods[] = { 3719 Authmethod authmethods[] = {
3020 #ifdef GSSAPI 3720 #ifdef GSSAPI
3021+ {"gssapi-keyex", 3721+ {"gssapi-keyex",
3022+ userauth_gsskeyex, 3722+ userauth_gsskeyex,
3023+ NULL, 3723+ NULL,
3024+ &options.gss_authentication, 3724+ &options.gss_keyex,
3025+ NULL}, 3725+ NULL},
3026 {"gssapi-with-mic", 3726 {"gssapi-with-mic",
3027 userauth_gssapi, 3727 userauth_gssapi,
3028 NULL, 3728 userauth_gssapi_cleanup,
3029@@ -686,25 +752,40 @@ userauth_gssapi(Authctxt *authctxt) 3729@@ -698,12 +766,25 @@ userauth_gssapi(struct ssh *ssh)
3030 static u_int mech = 0;
3031 OM_uint32 min; 3730 OM_uint32 min;
3032 int r, ok = 0; 3731 int r, ok = 0;
3732 gss_OID mech = NULL;
3033+ char *gss_host; 3733+ char *gss_host;
3034+ 3734+
3035+ if (options.gss_server_identity) 3735+ if (options.gss_server_identity)
3036+ gss_host = xstrdup(options.gss_server_identity); 3736+ gss_host = xstrdup(options.gss_server_identity);
3037+ else if (options.gss_trust_dns) 3737+ else if (options.gss_trust_dns)
3038+ gss_host = remote_hostname(active_state); 3738+ gss_host = remote_hostname(ssh);
3039+ else 3739+ else
3040+ gss_host = xstrdup(authctxt->host); 3740+ gss_host = xstrdup(authctxt->host);
3041 3741
3042 /* Try one GSSAPI method at a time, rather than sending them all at 3742 /* Try one GSSAPI method at a time, rather than sending them all at
3043 * once. */ 3743 * once. */
3044 3744
3045 if (gss_supported == NULL) 3745 if (authctxt->gss_supported_mechs == NULL)
3046- gss_indicate_mechs(&min, &gss_supported); 3746- gss_indicate_mechs(&min, &authctxt->gss_supported_mechs);
3047+ if (GSS_ERROR(gss_indicate_mechs(&min, &gss_supported))) { 3747+ if (GSS_ERROR(gss_indicate_mechs(&min,
3048+ gss_supported = NULL; 3748+ &authctxt->gss_supported_mechs))) {
3749+ authctxt->gss_supported_mechs = NULL;
3049+ free(gss_host); 3750+ free(gss_host);
3050+ return 0; 3751+ return 0;
3051+ } 3752+ }
3052 3753
3053 /* Check to see if the mechanism is usable before we offer it */ 3754 /* Check to see whether the mechanism is usable before we offer it */
3054 while (mech < gss_supported->count && !ok) { 3755 while (authctxt->mech_tried < authctxt->gss_supported_mechs->count &&
3756@@ -712,13 +793,15 @@ userauth_gssapi(struct ssh *ssh)
3757 elements[authctxt->mech_tried];
3055 /* My DER encoding requires length<128 */ 3758 /* My DER encoding requires length<128 */
3056 if (gss_supported->elements[mech].length < 128 && 3759 if (mech->length < 128 && ssh_gssapi_check_mechanism(&gssctxt,
3057 ssh_gssapi_check_mechanism(&gssctxt, 3760- mech, authctxt->host)) {
3058- &gss_supported->elements[mech], authctxt->host)) { 3761+ mech, gss_host, options.gss_client_identity)) {
3059+ &gss_supported->elements[mech], gss_host,
3060+ options.gss_client_identity)) {
3061 ok = 1; /* Mechanism works */ 3762 ok = 1; /* Mechanism works */
3062 } else { 3763 } else {
3063 mech++; 3764 authctxt->mech_tried++;
3064 } 3765 }
3065 } 3766 }
3066 3767
3067+ free(gss_host); 3768+ free(gss_host);
3068+ 3769+
3069 if (!ok) 3770 if (!ok || mech == NULL)
3070 return 0; 3771 return 0;
3071 3772
3072@@ -935,6 +1016,54 @@ input_gssapi_error(int type, u_int32_t plen, struct ssh *ssh) 3773@@ -958,6 +1041,55 @@ input_gssapi_error(int type, u_int32_t plen, struct ssh *ssh)
3073 free(lang); 3774 free(lang);
3074 return r; 3775 return r;
3075 } 3776 }
3076+ 3777+
3077+int 3778+int
3078+userauth_gsskeyex(Authctxt *authctxt) 3779+userauth_gsskeyex(struct ssh *ssh)
3079+{ 3780+{
3080+ struct ssh *ssh = active_state; /* XXX */ 3781+ struct sshbuf *b = NULL;
3081+ struct sshbuf *b; 3782+ Authctxt *authctxt = ssh->authctxt;
3082+ gss_buffer_desc gssbuf; 3783+ gss_buffer_desc gssbuf;
3083+ gss_buffer_desc mic = GSS_C_EMPTY_BUFFER; 3784+ gss_buffer_desc mic = GSS_C_EMPTY_BUFFER;
3084+ OM_uint32 ms; 3785+ OM_uint32 ms;
@@ -3089,12 +3790,13 @@ index 1675f3935..8c872a4fb 100644
3089+ return (0); 3790+ return (0);
3090+ 3791+
3091+ if (gss_kex_context == NULL) { 3792+ if (gss_kex_context == NULL) {
3092+ debug("No valid Key exchange context"); 3793+ debug("No valid Key exchange context");
3093+ return (0); 3794+ return (0);
3094+ } 3795+ }
3095+ 3796+
3096+ if ((b = sshbuf_new()) == NULL) 3797+ if ((b = sshbuf_new()) == NULL)
3097+ fatal("%s: sshbuf_new failed", __func__); 3798+ fatal("%s: sshbuf_new failed", __func__);
3799+
3098+ ssh_gssapi_buildmic(b, authctxt->server_user, authctxt->service, 3800+ ssh_gssapi_buildmic(b, authctxt->server_user, authctxt->service,
3099+ "gssapi-keyex"); 3801+ "gssapi-keyex");
3100+ 3802+
@@ -3123,9 +3825,9 @@ index 1675f3935..8c872a4fb 100644
3123+ 3825+
3124 #endif /* GSSAPI */ 3826 #endif /* GSSAPI */
3125 3827
3126 int 3828 static int
3127diff --git a/sshd.c b/sshd.c 3829diff --git a/sshd.c b/sshd.c
3128index ba26287ba..539a000fd 100644 3830index cbd3bce91..98680721b 100644
3129--- a/sshd.c 3831--- a/sshd.c
3130+++ b/sshd.c 3832+++ b/sshd.c
3131@@ -123,6 +123,10 @@ 3833@@ -123,6 +123,10 @@
@@ -3139,21 +3841,28 @@ index ba26287ba..539a000fd 100644
3139 /* Re-exec fds */ 3841 /* Re-exec fds */
3140 #define REEXEC_DEVCRYPTO_RESERVED_FD (STDERR_FILENO + 1) 3842 #define REEXEC_DEVCRYPTO_RESERVED_FD (STDERR_FILENO + 1)
3141 #define REEXEC_STARTUP_PIPE_FD (STDERR_FILENO + 2) 3843 #define REEXEC_STARTUP_PIPE_FD (STDERR_FILENO + 2)
3142@@ -1810,10 +1814,13 @@ main(int ac, char **av) 3844@@ -796,8 +800,8 @@ notify_hostkeys(struct ssh *ssh)
3845 }
3846 debug3("%s: sent %u hostkeys", __func__, nkeys);
3847 if (nkeys == 0)
3848- fatal("%s: no hostkeys", __func__);
3849- if ((r = sshpkt_send(ssh)) != 0)
3850+ debug3("%s: no hostkeys", __func__);
3851+ else if ((r = sshpkt_send(ssh)) != 0)
3852 sshpkt_fatal(ssh, r, "%s: send", __func__);
3853 sshbuf_free(buf);
3854 }
3855@@ -1769,7 +1773,8 @@ main(int ac, char **av)
3143 free(fp); 3856 free(fp);
3144 } 3857 }
3145 accumulate_host_timing_secret(cfg, NULL); 3858 accumulate_host_timing_secret(cfg, NULL);
3146+#ifndef GSSAPI 3859- if (!sensitive_data.have_ssh2_key) {
3147+ /* The GSSAPI key exchange can run without a host key */ 3860+ /* The GSSAPI key exchange can run without a host key */
3148 if (!sensitive_data.have_ssh2_key) { 3861+ if (!sensitive_data.have_ssh2_key && !options.gss_keyex) {
3149 logit("sshd: no hostkeys available -- exiting."); 3862 logit("sshd: no hostkeys available -- exiting.");
3150 exit(1); 3863 exit(1);
3151 } 3864 }
3152+#endif 3865@@ -2064,6 +2069,60 @@ main(int ac, char **av)
3153
3154 /*
3155 * Load certificates. They are stored in an array at identical
3156@@ -2104,6 +2111,60 @@ main(int ac, char **av)
3157 rdomain == NULL ? "" : "\""); 3866 rdomain == NULL ? "" : "\"");
3158 free(laddr); 3867 free(laddr);
3159 3868
@@ -3214,18 +3923,18 @@ index ba26287ba..539a000fd 100644
3214 /* 3923 /*
3215 * We don't want to listen forever unless the other side 3924 * We don't want to listen forever unless the other side
3216 * successfully authenticates itself. So we set up an alarm which is 3925 * successfully authenticates itself. So we set up an alarm which is
3217@@ -2287,6 +2348,48 @@ do_ssh2_kex(void) 3926@@ -2260,6 +2319,48 @@ do_ssh2_kex(struct ssh *ssh)
3218 myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = compat_pkalg_proposal( 3927 myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = compat_pkalg_proposal(
3219 list_hostkey_types()); 3928 list_hostkey_types());
3220 3929
3221+#ifdef GSSAPI 3930+#if defined(GSSAPI) && defined(WITH_OPENSSL)
3222+ { 3931+ {
3223+ char *orig; 3932+ char *orig;
3224+ char *gss = NULL; 3933+ char *gss = NULL;
3225+ char *newstr = NULL; 3934+ char *newstr = NULL;
3226+ orig = myproposal[PROPOSAL_KEX_ALGS]; 3935+ orig = myproposal[PROPOSAL_KEX_ALGS];
3227+ 3936+
3228+ /* 3937+ /*
3229+ * If we don't have a host key, then there's no point advertising 3938+ * If we don't have a host key, then there's no point advertising
3230+ * the other key exchange algorithms 3939+ * the other key exchange algorithms
3231+ */ 3940+ */
@@ -3245,10 +3954,10 @@ index ba26287ba..539a000fd 100644
3245+ else if (orig) 3954+ else if (orig)
3246+ newstr = orig; 3955+ newstr = orig;
3247+ 3956+
3248+ /* 3957+ /*
3249+ * If we've got GSSAPI mechanisms, then we've got the 'null' host 3958+ * If we've got GSSAPI mechanisms, then we've got the 'null' host
3250+ * key alg, but we can't tell people about it unless its the only 3959+ * key alg, but we can't tell people about it unless its the only
3251+ * host key algorithm we support 3960+ * host key algorithm we support
3252+ */ 3961+ */
3253+ if (gss && (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS])) == 0) 3962+ if (gss && (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS])) == 0)
3254+ myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = "null"; 3963+ myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = "null";
@@ -3261,22 +3970,28 @@ index ba26287ba..539a000fd 100644
3261+#endif 3970+#endif
3262+ 3971+
3263 /* start key exchange */ 3972 /* start key exchange */
3264 if ((r = kex_setup(active_state, myproposal)) != 0) 3973 if ((r = kex_setup(ssh, myproposal)) != 0)
3265 fatal("kex_setup: %s", ssh_err(r)); 3974 fatal("kex_setup: %s", ssh_err(r));
3266@@ -2304,6 +2407,13 @@ do_ssh2_kex(void) 3975@@ -2275,7 +2376,18 @@ do_ssh2_kex(struct ssh *ssh)
3976 # ifdef OPENSSL_HAS_ECC
3977 kex->kex[KEX_ECDH_SHA2] = kex_gen_server;
3267 # endif 3978 # endif
3268 #endif 3979-#endif
3269 kex->kex[KEX_C25519_SHA256] = kexc25519_server; 3980+# ifdef GSSAPI
3270+#ifdef GSSAPI
3271+ if (options.gss_keyex) { 3981+ if (options.gss_keyex) {
3272+ kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server; 3982+ kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server;
3273+ kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_server; 3983+ kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_server;
3274+ kex->kex[KEX_GSS_GEX_SHA1] = kexgss_server; 3984+ kex->kex[KEX_GSS_GRP14_SHA256] = kexgss_server;
3985+ kex->kex[KEX_GSS_GRP16_SHA512] = kexgss_server;
3986+ kex->kex[KEX_GSS_GEX_SHA1] = kexgssgex_server;
3987+ kex->kex[KEX_GSS_NISTP256_SHA256] = kexgss_server;
3988+ kex->kex[KEX_GSS_C25519_SHA256] = kexgss_server;
3275+ } 3989+ }
3276+#endif 3990+# endif
3277 kex->server = 1; 3991+#endif /* WITH_OPENSSL */
3278 kex->client_version_string=client_version_string; 3992 kex->kex[KEX_C25519_SHA256] = kex_gen_server;
3279 kex->server_version_string=server_version_string; 3993 kex->kex[KEX_KEM_SNTRUP4591761X25519_SHA512] = kex_gen_server;
3994 kex->load_host_public_key=&get_hostkey_public_by_type;
3280diff --git a/sshd_config b/sshd_config 3995diff --git a/sshd_config b/sshd_config
3281index 19b7c91a1..2c48105f8 100644 3996index 19b7c91a1..2c48105f8 100644
3282--- a/sshd_config 3997--- a/sshd_config
@@ -3291,35 +4006,55 @@ index 19b7c91a1..2c48105f8 100644
3291 # Set this to 'yes' to enable PAM authentication, account processing, 4006 # Set this to 'yes' to enable PAM authentication, account processing,
3292 # and session processing. If this is enabled, PAM authentication will 4007 # and session processing. If this is enabled, PAM authentication will
3293diff --git a/sshd_config.5 b/sshd_config.5 4008diff --git a/sshd_config.5 b/sshd_config.5
3294index c6484370b..985eef5a2 100644 4009index b224f2929..2baa6622b 100644
3295--- a/sshd_config.5 4010--- a/sshd_config.5
3296+++ b/sshd_config.5 4011+++ b/sshd_config.5
3297@@ -648,6 +648,11 @@ The default is 4012@@ -653,6 +653,11 @@ Specifies whether to automatically destroy the user's credentials cache
3298 Specifies whether user authentication based on GSSAPI is allowed. 4013 on logout.
3299 The default is 4014 The default is
3300 .Cm no . 4015 .Cm yes .
3301+.It Cm GSSAPIKeyExchange 4016+.It Cm GSSAPIKeyExchange
3302+Specifies whether key exchange based on GSSAPI is allowed. GSSAPI key exchange 4017+Specifies whether key exchange based on GSSAPI is allowed. GSSAPI key exchange
3303+doesn't rely on ssh keys to verify host identity. 4018+doesn't rely on ssh keys to verify host identity.
3304+The default is 4019+The default is
3305+.Cm no . 4020+.Cm no .
3306 .It Cm GSSAPICleanupCredentials 4021 .It Cm GSSAPIStrictAcceptorCheck
3307 Specifies whether to automatically destroy the user's credentials cache 4022 Determines whether to be strict about the identity of the GSSAPI acceptor
3308 on logout. 4023 a client authenticates against.
3309@@ -667,6 +672,11 @@ machine's default store. 4024@@ -667,6 +672,31 @@ machine's default store.
3310 This facility is provided to assist with operation on multi homed machines. 4025 This facility is provided to assist with operation on multi homed machines.
3311 The default is 4026 The default is
3312 .Cm yes . 4027 .Cm yes .
3313+.It Cm GSSAPIStoreCredentialsOnRekey 4028+.It Cm GSSAPIStoreCredentialsOnRekey
3314+Controls whether the user's GSSAPI credentials should be updated following a 4029+Controls whether the user's GSSAPI credentials should be updated following a
3315+successful connection rekeying. This option can be used to accepted renewed 4030+successful connection rekeying. This option can be used to accepted renewed
3316+or updated credentials from a compatible client. The default is 4031+or updated credentials from a compatible client. The default is
3317+.Cm no . 4032+.Dq no .
4033+.Pp
4034+For this to work
4035+.Cm GSSAPIKeyExchange
4036+needs to be enabled in the server and also used by the client.
4037+.It Cm GSSAPIKexAlgorithms
4038+The list of key exchange algorithms that are accepted by GSSAPI
4039+key exchange. Possible values are
4040+.Bd -literal -offset 3n
4041+gss-gex-sha1-,
4042+gss-group1-sha1-,
4043+gss-group14-sha1-,
4044+gss-group14-sha256-,
4045+gss-group16-sha512-,
4046+gss-nistp256-sha256-,
4047+gss-curve25519-sha256-
4048+.Ed
4049+.Pp
4050+The default is
4051+.Dq gss-gex-sha1-,gss-group14-sha1- .
4052+This option only applies to protocol version 2 connections using GSSAPI.
3318 .It Cm HostbasedAcceptedKeyTypes 4053 .It Cm HostbasedAcceptedKeyTypes
3319 Specifies the key types that will be accepted for hostbased authentication 4054 Specifies the key types that will be accepted for hostbased authentication
3320 as a list of comma-separated patterns. 4055 as a list of comma-separated patterns.
3321diff --git a/sshkey.c b/sshkey.c 4056diff --git a/sshkey.c b/sshkey.c
3322index 6555c5ef8..a85c185fc 100644 4057index ad1957762..789cd61ef 100644
3323--- a/sshkey.c 4058--- a/sshkey.c
3324+++ b/sshkey.c 4059+++ b/sshkey.c
3325@@ -135,6 +135,7 @@ static const struct keytype keytypes[] = { 4060@@ -135,6 +135,7 @@ static const struct keytype keytypes[] = {
@@ -3340,10 +4075,10 @@ index 6555c5ef8..a85c185fc 100644
3340 if (!include_sigonly && kt->sigonly) 4075 if (!include_sigonly && kt->sigonly)
3341 continue; 4076 continue;
3342diff --git a/sshkey.h b/sshkey.h 4077diff --git a/sshkey.h b/sshkey.h
3343index f6a007fdf..f54deb0c0 100644 4078index a91e60436..c11106c93 100644
3344--- a/sshkey.h 4079--- a/sshkey.h
3345+++ b/sshkey.h 4080+++ b/sshkey.h
3346@@ -64,6 +64,7 @@ enum sshkey_types { 4081@@ -65,6 +65,7 @@ enum sshkey_types {
3347 KEY_ED25519_CERT, 4082 KEY_ED25519_CERT,
3348 KEY_XMSS, 4083 KEY_XMSS,
3349 KEY_XMSS_CERT, 4084 KEY_XMSS_CERT,