diff options
Diffstat (limited to 'debian/patches/gssapi.patch')
-rw-r--r-- | debian/patches/gssapi.patch | 2539 |
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 @@ | |||
1 | From 72b1d308e6400194ef6e4e7dd45bfa48fa39b5e6 Mon Sep 17 00:00:00 2001 | 1 | From 7ce79be85036c4b36937f1b1ba85f6094068412c Mon Sep 17 00:00:00 2001 |
2 | From: Simon Wilkinson <simon@sxw.org.uk> | 2 | From: Simon Wilkinson <simon@sxw.org.uk> |
3 | Date: Sun, 9 Feb 2014 16:09:48 +0000 | 3 | Date: Sun, 9 Feb 2014 16:09:48 +0000 |
4 | Subject: GSSAPI key exchange support | 4 | Subject: 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 |
17 | security history. | 17 | security history. |
18 | 18 | ||
19 | Origin: other, https://github.com/openssh-gsskex/openssh-gsskex/commits/debian/master | ||
19 | Bug: https://bugzilla.mindrot.org/show_bug.cgi?id=1242 | 20 | Bug: https://bugzilla.mindrot.org/show_bug.cgi?id=1242 |
20 | Last-Updated: 2018-10-20 | 21 | Last-Updated: 2019-06-05 |
21 | 22 | ||
22 | Patch-Name: gssapi.patch | 23 | Patch-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 | ||
66 | diff --git a/ChangeLog.gssapi b/ChangeLog.gssapi | ||
67 | new file mode 100644 | ||
68 | index 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> | ||
185 | diff --git a/Makefile.in b/Makefile.in | 69 | diff --git a/Makefile.in b/Makefile.in |
186 | index 126b2c742..70050ffb6 100644 | 70 | index 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 | } |
257 | diff --git a/auth.c b/auth.c | 141 | diff --git a/auth.c b/auth.c |
258 | index 3ca3762cc..d8e6b4a3d 100644 | 142 | index 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 |
371 | diff --git a/auth2-gss.c b/auth2-gss.c | 255 | diff --git a/auth2-gss.c b/auth2-gss.c |
372 | index 9351e0428..1f12bb113 100644 | 256 | index 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, |
464 | diff --git a/auth2.c b/auth2.c | 350 | diff --git a/auth2.c b/auth2.c |
465 | index 4d19957a6..a77742819 100644 | 351 | index 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); |
602 | diff --git a/clientloop.c b/clientloop.c | 488 | diff --git a/clientloop.c b/clientloop.c |
603 | index 8d312cdaa..1464634b0 100644 | 489 | index 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 | |||
637 | diff --git a/config.h.in b/config.h.in | ||
638 | index 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 | ||
661 | diff --git a/configure.ac b/configure.ac | 523 | diff --git a/configure.ac b/configure.ac |
662 | index 7379ab358..023e7cc55 100644 | 524 | index 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]) |
696 | diff --git a/gss-genr.c b/gss-genr.c | 558 | diff --git a/gss-genr.c b/gss-genr.c |
697 | index d56257b4a..491e62cee 100644 | 559 | index 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 */ |
1061 | diff --git a/gss-serv-krb5.c b/gss-serv-krb5.c | 941 | diff --git a/gss-serv-krb5.c b/gss-serv-krb5.c |
1062 | index a151bc1e4..90f8692f5 100644 | 942 | index 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 */ |
1187 | diff --git a/gss-serv.c b/gss-serv.c | 1067 | diff --git a/gss-serv.c b/gss-serv.c |
1188 | index ab3a15f0f..6c087a1b1 100644 | 1068 | index 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 */ |
1341 | diff --git a/hmac.c b/hmac.c | ||
1342 | index 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" | ||
1458 | diff --git a/kex.c b/kex.c | 1353 | diff --git a/kex.c b/kex.c |
1459 | index 25f9f66f6..fb5bfaea5 100644 | 1354 | index 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); | ||
1509 | diff --git a/kex.h b/kex.h | 1476 | diff --git a/kex.h b/kex.h |
1510 | index 593de1208..4e5ead839 100644 | 1477 | index 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))); | ||
1546 | diff --git a/kexdh.c b/kexdh.c | ||
1547 | index 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: | ||
1574 | diff --git a/kexgen.c b/kexgen.c | ||
1575 | index 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, | ||
1548 | diff --git a/kexgssc.c b/kexgssc.c | 1587 | diff --git a/kexgssc.c b/kexgssc.c |
1549 | new file mode 100644 | 1588 | new file mode 100644 |
1550 | index 000000000..3c8ae08dd | 1589 | index 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 */ | ||
1895 | diff --git a/kexgsss.c b/kexgsss.c | 2199 | diff --git a/kexgsss.c b/kexgsss.c |
1896 | new file mode 100644 | 2200 | new file mode 100644 |
1897 | index 000000000..18070f1d7 | 2201 | index 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) */ |
2679 | diff --git a/mac.c b/mac.c | ||
2680 | index 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" | ||
2201 | diff --git a/monitor.c b/monitor.c | 2691 | diff --git a/monitor.c b/monitor.c |
2202 | index 531b2993a..eabc1e89b 100644 | 2692 | index 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 | ||
2409 | diff --git a/monitor.h b/monitor.h | 2925 | diff --git a/monitor.h b/monitor.h |
2410 | index 16047299f..44fbed589 100644 | 2926 | index 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; |
2423 | diff --git a/monitor_wrap.c b/monitor_wrap.c | 2938 | diff --git a/monitor_wrap.c b/monitor_wrap.c |
2424 | index 732fb3476..1865a122a 100644 | 2939 | index 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 */ |
2492 | diff --git a/monitor_wrap.h b/monitor_wrap.h | 3017 | diff --git a/monitor_wrap.h b/monitor_wrap.h |
2493 | index 644da081d..7f93144ff 100644 | 3018 | index 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 |
2508 | diff --git a/opacket.c b/opacket.c | ||
2509 | index 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 | |||
2521 | diff --git a/opacket.h b/opacket.h | ||
2522 | index 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); | ||
2534 | diff --git a/readconf.c b/readconf.c | 3033 | diff --git a/readconf.c b/readconf.c |
2535 | index 433811521..36bc5e59a 100644 | 3034 | index 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); | ||
2627 | diff --git a/readconf.h b/readconf.h | 3168 | diff --git a/readconf.h b/readconf.h |
2628 | index fc7e38251..8e4900d01 100644 | 3169 | index 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. */ |
2644 | diff --git a/servconf.c b/servconf.c | 3186 | diff --git a/servconf.c b/servconf.c |
2645 | index 932d363bb..4668b8a45 100644 | 3187 | index 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, |
2736 | diff --git a/servconf.h b/servconf.h | 3305 | diff --git a/servconf.h b/servconf.h |
2737 | index 0175e00e8..3b76da816 100644 | 3306 | index 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 */ |
3321 | diff --git a/session.c b/session.c | ||
3322 | index 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 */ | ||
2751 | diff --git a/ssh-gss.h b/ssh-gss.h | 3347 | diff --git a/ssh-gss.h b/ssh-gss.h |
2752 | index 36180d07a..350ce7882 100644 | 3348 | index 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 */ |
3467 | diff --git a/ssh.1 b/ssh.1 | ||
3468 | index 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 | ||
3494 | diff --git a/ssh.c b/ssh.c | ||
3495 | index 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 | } | ||
2855 | diff --git a/ssh_config b/ssh_config | 3516 | diff --git a/ssh_config b/ssh_config |
2856 | index c12f5ef52..bcb9f153d 100644 | 3517 | index 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 |
2868 | diff --git a/ssh_config.5 b/ssh_config.5 | 3529 | diff --git a/ssh_config.5 b/ssh_config.5 |
2869 | index 4d5b01d3e..16c79368a 100644 | 3530 | index 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 |
2915 | diff --git a/sshconnect2.c b/sshconnect2.c | 3601 | diff --git a/sshconnect2.c b/sshconnect2.c |
2916 | index 1675f3935..8c872a4fb 100644 | 3602 | index 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 |
3127 | diff --git a/sshd.c b/sshd.c | 3829 | diff --git a/sshd.c b/sshd.c |
3128 | index ba26287ba..539a000fd 100644 | 3830 | index 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; | ||
3280 | diff --git a/sshd_config b/sshd_config | 3995 | diff --git a/sshd_config b/sshd_config |
3281 | index 19b7c91a1..2c48105f8 100644 | 3996 | index 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 |
3293 | diff --git a/sshd_config.5 b/sshd_config.5 | 4008 | diff --git a/sshd_config.5 b/sshd_config.5 |
3294 | index c6484370b..985eef5a2 100644 | 4009 | index 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. |
3321 | diff --git a/sshkey.c b/sshkey.c | 4056 | diff --git a/sshkey.c b/sshkey.c |
3322 | index 6555c5ef8..a85c185fc 100644 | 4057 | index 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; |
3342 | diff --git a/sshkey.h b/sshkey.h | 4077 | diff --git a/sshkey.h b/sshkey.h |
3343 | index f6a007fdf..f54deb0c0 100644 | 4078 | index 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, |