summaryrefslogtreecommitdiff
path: root/sshconnect2.c
diff options
context:
space:
mode:
authorSimon Wilkinson <simon@sxw.org.uk>2014-02-09 16:09:48 +0000
committerColin Watson <cjwatson@debian.org>2017-01-16 15:02:41 +0000
commit48fbb156bdc676fb6ba6817770e4e971fbf85b1f (patch)
treef35c67c09472bddc3337b1c74b0cb6a1d9b58670 /sshconnect2.c
parent971a7653746a6972b907dfe0ce139c06e4a6f482 (diff)
GSSAPI key exchange support
This patch has been rejected upstream: "None of the OpenSSH developers are in favour of adding this, and this situation has not changed for several years. This is not a slight on Simon's patch, which is of fine quality, but just that a) we don't trust GSSAPI implementations that much and b) we don't like adding new KEX since they are pre-auth attack surface. This one is particularly scary, since it requires hooks out to typically root-owned system resources." However, quite a lot of people rely on this in Debian, and it's better to have it merged into the main openssh package rather than having separate -krb5 packages (as we used to have). It seems to have a generally good security history. Bug: https://bugzilla.mindrot.org/show_bug.cgi?id=1242 Last-Updated: 2017-01-16 Patch-Name: gssapi.patch
Diffstat (limited to 'sshconnect2.c')
-rw-r--r--sshconnect2.c131
1 files changed, 127 insertions, 4 deletions
diff --git a/sshconnect2.c b/sshconnect2.c
index 103a2b36a..c35a0bd50 100644
--- a/sshconnect2.c
+++ b/sshconnect2.c
@@ -162,6 +162,11 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port)
162 struct kex *kex; 162 struct kex *kex;
163 int r; 163 int r;
164 164
165#ifdef GSSAPI
166 char *orig = NULL, *gss = NULL;
167 char *gss_host = NULL;
168#endif
169
165 xxx_host = host; 170 xxx_host = host;
166 xxx_hostaddr = hostaddr; 171 xxx_hostaddr = hostaddr;
167 172
@@ -192,6 +197,35 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port)
192 order_hostkeyalgs(host, hostaddr, port)); 197 order_hostkeyalgs(host, hostaddr, port));
193 } 198 }
194 199
200#ifdef GSSAPI
201 if (options.gss_keyex) {
202 /* Add the GSSAPI mechanisms currently supported on this
203 * client to the key exchange algorithm proposal */
204 orig = myproposal[PROPOSAL_KEX_ALGS];
205
206 if (options.gss_server_identity)
207 gss_host = xstrdup(options.gss_server_identity);
208 else if (options.gss_trust_dns)
209 gss_host = remote_hostname(active_state);
210 else
211 gss_host = xstrdup(host);
212
213 gss = ssh_gssapi_client_mechanisms(gss_host,
214 options.gss_client_identity);
215 if (gss) {
216 debug("Offering GSSAPI proposal: %s", gss);
217 xasprintf(&myproposal[PROPOSAL_KEX_ALGS],
218 "%s,%s", gss, orig);
219
220 /* If we've got GSSAPI algorithms, then we also
221 * support the 'null' hostkey, as a last resort */
222 orig = myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS];
223 xasprintf(&myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS],
224 "%s,null", orig);
225 }
226 }
227#endif
228
195 if (options.rekey_limit || options.rekey_interval) 229 if (options.rekey_limit || options.rekey_interval)
196 packet_set_rekey_limits((u_int32_t)options.rekey_limit, 230 packet_set_rekey_limits((u_int32_t)options.rekey_limit,
197 (time_t)options.rekey_interval); 231 (time_t)options.rekey_interval);
@@ -213,15 +247,41 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port)
213# endif 247# endif
214#endif 248#endif
215 kex->kex[KEX_C25519_SHA256] = kexc25519_client; 249 kex->kex[KEX_C25519_SHA256] = kexc25519_client;
250#ifdef GSSAPI
251 if (options.gss_keyex) {
252 kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_client;
253 kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_client;
254 kex->kex[KEX_GSS_GEX_SHA1] = kexgss_client;
255 }
256#endif
216 kex->client_version_string=client_version_string; 257 kex->client_version_string=client_version_string;
217 kex->server_version_string=server_version_string; 258 kex->server_version_string=server_version_string;
218 kex->verify_host_key=&verify_host_key_callback; 259 kex->verify_host_key=&verify_host_key_callback;
219 260
261#ifdef GSSAPI
262 if (options.gss_keyex) {
263 kex->gss_deleg_creds = options.gss_deleg_creds;
264 kex->gss_trust_dns = options.gss_trust_dns;
265 kex->gss_client = options.gss_client_identity;
266 kex->gss_host = gss_host;
267 }
268#endif
269
220 dispatch_run(DISPATCH_BLOCK, &kex->done, active_state); 270 dispatch_run(DISPATCH_BLOCK, &kex->done, active_state);
221 271
222 /* remove ext-info from the KEX proposals for rekeying */ 272 /* remove ext-info from the KEX proposals for rekeying */
223 myproposal[PROPOSAL_KEX_ALGS] = 273 myproposal[PROPOSAL_KEX_ALGS] =
224 compat_kex_proposal(options.kex_algorithms); 274 compat_kex_proposal(options.kex_algorithms);
275#ifdef GSSAPI
276 /* repair myproposal after it was crumpled by the */
277 /* ext-info removal above */
278 if (gss) {
279 orig = myproposal[PROPOSAL_KEX_ALGS];
280 xasprintf(&myproposal[PROPOSAL_KEX_ALGS],
281 "%s,%s", gss, orig);
282 free(gss);
283 }
284#endif
225 if ((r = kex_prop2buf(kex->my, myproposal)) != 0) 285 if ((r = kex_prop2buf(kex->my, myproposal)) != 0)
226 fatal("kex_prop2buf: %s", ssh_err(r)); 286 fatal("kex_prop2buf: %s", ssh_err(r));
227 287
@@ -311,6 +371,7 @@ int input_gssapi_token(int type, u_int32_t, void *);
311int input_gssapi_hash(int type, u_int32_t, void *); 371int input_gssapi_hash(int type, u_int32_t, void *);
312int input_gssapi_error(int, u_int32_t, void *); 372int input_gssapi_error(int, u_int32_t, void *);
313int input_gssapi_errtok(int, u_int32_t, void *); 373int input_gssapi_errtok(int, u_int32_t, void *);
374int userauth_gsskeyex(Authctxt *authctxt);
314#endif 375#endif
315 376
316void userauth(Authctxt *, char *); 377void userauth(Authctxt *, char *);
@@ -327,6 +388,11 @@ static char *authmethods_get(void);
327 388
328Authmethod authmethods[] = { 389Authmethod authmethods[] = {
329#ifdef GSSAPI 390#ifdef GSSAPI
391 {"gssapi-keyex",
392 userauth_gsskeyex,
393 NULL,
394 &options.gss_authentication,
395 NULL},
330 {"gssapi-with-mic", 396 {"gssapi-with-mic",
331 userauth_gssapi, 397 userauth_gssapi,
332 NULL, 398 NULL,
@@ -652,25 +718,40 @@ userauth_gssapi(Authctxt *authctxt)
652 static u_int mech = 0; 718 static u_int mech = 0;
653 OM_uint32 min; 719 OM_uint32 min;
654 int ok = 0; 720 int ok = 0;
721 char *gss_host;
722
723 if (options.gss_server_identity)
724 gss_host = xstrdup(options.gss_server_identity);
725 else if (options.gss_trust_dns)
726 gss_host = remote_hostname(active_state);
727 else
728 gss_host = xstrdup(authctxt->host);
655 729
656 /* Try one GSSAPI method at a time, rather than sending them all at 730 /* Try one GSSAPI method at a time, rather than sending them all at
657 * once. */ 731 * once. */
658 732
659 if (gss_supported == NULL) 733 if (gss_supported == NULL)
660 gss_indicate_mechs(&min, &gss_supported); 734 if (GSS_ERROR(gss_indicate_mechs(&min, &gss_supported))) {
735 gss_supported = NULL;
736 free(gss_host);
737 return 0;
738 }
661 739
662 /* Check to see if the mechanism is usable before we offer it */ 740 /* Check to see if the mechanism is usable before we offer it */
663 while (mech < gss_supported->count && !ok) { 741 while (mech < gss_supported->count && !ok) {
664 /* My DER encoding requires length<128 */ 742 /* My DER encoding requires length<128 */
665 if (gss_supported->elements[mech].length < 128 && 743 if (gss_supported->elements[mech].length < 128 &&
666 ssh_gssapi_check_mechanism(&gssctxt, 744 ssh_gssapi_check_mechanism(&gssctxt,
667 &gss_supported->elements[mech], authctxt->host)) { 745 &gss_supported->elements[mech], gss_host,
746 options.gss_client_identity)) {
668 ok = 1; /* Mechanism works */ 747 ok = 1; /* Mechanism works */
669 } else { 748 } else {
670 mech++; 749 mech++;
671 } 750 }
672 } 751 }
673 752
753 free(gss_host);
754
674 if (!ok) 755 if (!ok)
675 return 0; 756 return 0;
676 757
@@ -761,8 +842,8 @@ input_gssapi_response(int type, u_int32_t plen, void *ctxt)
761{ 842{
762 Authctxt *authctxt = ctxt; 843 Authctxt *authctxt = ctxt;
763 Gssctxt *gssctxt; 844 Gssctxt *gssctxt;
764 int oidlen; 845 u_int oidlen;
765 char *oidv; 846 u_char *oidv;
766 847
767 if (authctxt == NULL) 848 if (authctxt == NULL)
768 fatal("input_gssapi_response: no authentication context"); 849 fatal("input_gssapi_response: no authentication context");
@@ -875,6 +956,48 @@ input_gssapi_error(int type, u_int32_t plen, void *ctxt)
875 free(lang); 956 free(lang);
876 return 0; 957 return 0;
877} 958}
959
960int
961userauth_gsskeyex(Authctxt *authctxt)
962{
963 Buffer b;
964 gss_buffer_desc gssbuf;
965 gss_buffer_desc mic = GSS_C_EMPTY_BUFFER;
966 OM_uint32 ms;
967
968 static int attempt = 0;
969 if (attempt++ >= 1)
970 return (0);
971
972 if (gss_kex_context == NULL) {
973 debug("No valid Key exchange context");
974 return (0);
975 }
976
977 ssh_gssapi_buildmic(&b, authctxt->server_user, authctxt->service,
978 "gssapi-keyex");
979
980 gssbuf.value = buffer_ptr(&b);
981 gssbuf.length = buffer_len(&b);
982
983 if (GSS_ERROR(ssh_gssapi_sign(gss_kex_context, &gssbuf, &mic))) {
984 buffer_free(&b);
985 return (0);
986 }
987
988 packet_start(SSH2_MSG_USERAUTH_REQUEST);
989 packet_put_cstring(authctxt->server_user);
990 packet_put_cstring(authctxt->service);
991 packet_put_cstring(authctxt->method->name);
992 packet_put_string(mic.value, mic.length);
993 packet_send();
994
995 buffer_free(&b);
996 gss_release_buffer(&ms, &mic);
997
998 return (1);
999}
1000
878#endif /* GSSAPI */ 1001#endif /* GSSAPI */
879 1002
880int 1003int