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>2018-08-24 17:49:04 +0100
commite6c7c11ac2576ac62334616bd4408bf64140bba7 (patch)
tree0625a34b2eafa6425602cb8c7185fbddc2d05fd7 /sshconnect2.c
parente6547182a54f0f268ee36e7c99319eeddffbaff2 (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: 2018-08-24 Patch-Name: gssapi.patch
Diffstat (limited to 'sshconnect2.c')
-rw-r--r--sshconnect2.c133
1 files changed, 131 insertions, 2 deletions
diff --git a/sshconnect2.c b/sshconnect2.c
index 10e4f0a08..c6a1b1271 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
@@ -194,6 +199,35 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port)
194 order_hostkeyalgs(host, hostaddr, port)); 199 order_hostkeyalgs(host, hostaddr, port));
195 } 200 }
196 201
202#ifdef GSSAPI
203 if (options.gss_keyex) {
204 /* Add the GSSAPI mechanisms currently supported on this
205 * client to the key exchange algorithm proposal */
206 orig = myproposal[PROPOSAL_KEX_ALGS];
207
208 if (options.gss_server_identity)
209 gss_host = xstrdup(options.gss_server_identity);
210 else if (options.gss_trust_dns)
211 gss_host = remote_hostname(active_state);
212 else
213 gss_host = xstrdup(host);
214
215 gss = ssh_gssapi_client_mechanisms(gss_host,
216 options.gss_client_identity);
217 if (gss) {
218 debug("Offering GSSAPI proposal: %s", gss);
219 xasprintf(&myproposal[PROPOSAL_KEX_ALGS],
220 "%s,%s", gss, orig);
221
222 /* If we've got GSSAPI algorithms, then we also
223 * support the 'null' hostkey, as a last resort */
224 orig = myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS];
225 xasprintf(&myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS],
226 "%s,null", orig);
227 }
228 }
229#endif
230
197 if (options.rekey_limit || options.rekey_interval) 231 if (options.rekey_limit || options.rekey_interval)
198 packet_set_rekey_limits(options.rekey_limit, 232 packet_set_rekey_limits(options.rekey_limit,
199 options.rekey_interval); 233 options.rekey_interval);
@@ -215,15 +249,41 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port)
215# endif 249# endif
216#endif 250#endif
217 kex->kex[KEX_C25519_SHA256] = kexc25519_client; 251 kex->kex[KEX_C25519_SHA256] = kexc25519_client;
252#ifdef GSSAPI
253 if (options.gss_keyex) {
254 kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_client;
255 kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_client;
256 kex->kex[KEX_GSS_GEX_SHA1] = kexgss_client;
257 }
258#endif
218 kex->client_version_string=client_version_string; 259 kex->client_version_string=client_version_string;
219 kex->server_version_string=server_version_string; 260 kex->server_version_string=server_version_string;
220 kex->verify_host_key=&verify_host_key_callback; 261 kex->verify_host_key=&verify_host_key_callback;
221 262
263#ifdef GSSAPI
264 if (options.gss_keyex) {
265 kex->gss_deleg_creds = options.gss_deleg_creds;
266 kex->gss_trust_dns = options.gss_trust_dns;
267 kex->gss_client = options.gss_client_identity;
268 kex->gss_host = gss_host;
269 }
270#endif
271
222 ssh_dispatch_run_fatal(active_state, DISPATCH_BLOCK, &kex->done); 272 ssh_dispatch_run_fatal(active_state, DISPATCH_BLOCK, &kex->done);
223 273
224 /* remove ext-info from the KEX proposals for rekeying */ 274 /* remove ext-info from the KEX proposals for rekeying */
225 myproposal[PROPOSAL_KEX_ALGS] = 275 myproposal[PROPOSAL_KEX_ALGS] =
226 compat_kex_proposal(options.kex_algorithms); 276 compat_kex_proposal(options.kex_algorithms);
277#ifdef GSSAPI
278 /* repair myproposal after it was crumpled by the */
279 /* ext-info removal above */
280 if (gss) {
281 orig = myproposal[PROPOSAL_KEX_ALGS];
282 xasprintf(&myproposal[PROPOSAL_KEX_ALGS],
283 "%s,%s", gss, orig);
284 free(gss);
285 }
286#endif
227 if ((r = kex_prop2buf(kex->my, myproposal)) != 0) 287 if ((r = kex_prop2buf(kex->my, myproposal)) != 0)
228 fatal("kex_prop2buf: %s", ssh_err(r)); 288 fatal("kex_prop2buf: %s", ssh_err(r));
229 289
@@ -314,6 +374,7 @@ int input_gssapi_token(int type, u_int32_t, struct ssh *);
314int input_gssapi_hash(int type, u_int32_t, struct ssh *); 374int input_gssapi_hash(int type, u_int32_t, struct ssh *);
315int input_gssapi_error(int, u_int32_t, struct ssh *); 375int input_gssapi_error(int, u_int32_t, struct ssh *);
316int input_gssapi_errtok(int, u_int32_t, struct ssh *); 376int input_gssapi_errtok(int, u_int32_t, struct ssh *);
377int userauth_gsskeyex(Authctxt *authctxt);
317#endif 378#endif
318 379
319void userauth(Authctxt *, char *); 380void userauth(Authctxt *, char *);
@@ -330,6 +391,11 @@ static char *authmethods_get(void);
330 391
331Authmethod authmethods[] = { 392Authmethod authmethods[] = {
332#ifdef GSSAPI 393#ifdef GSSAPI
394 {"gssapi-keyex",
395 userauth_gsskeyex,
396 NULL,
397 &options.gss_authentication,
398 NULL},
333 {"gssapi-with-mic", 399 {"gssapi-with-mic",
334 userauth_gssapi, 400 userauth_gssapi,
335 NULL, 401 NULL,
@@ -657,25 +723,40 @@ userauth_gssapi(Authctxt *authctxt)
657 static u_int mech = 0; 723 static u_int mech = 0;
658 OM_uint32 min; 724 OM_uint32 min;
659 int r, ok = 0; 725 int r, ok = 0;
726 char *gss_host;
727
728 if (options.gss_server_identity)
729 gss_host = xstrdup(options.gss_server_identity);
730 else if (options.gss_trust_dns)
731 gss_host = remote_hostname(active_state);
732 else
733 gss_host = xstrdup(authctxt->host);
660 734
661 /* Try one GSSAPI method at a time, rather than sending them all at 735 /* Try one GSSAPI method at a time, rather than sending them all at
662 * once. */ 736 * once. */
663 737
664 if (gss_supported == NULL) 738 if (gss_supported == NULL)
665 gss_indicate_mechs(&min, &gss_supported); 739 if (GSS_ERROR(gss_indicate_mechs(&min, &gss_supported))) {
740 gss_supported = NULL;
741 free(gss_host);
742 return 0;
743 }
666 744
667 /* Check to see if the mechanism is usable before we offer it */ 745 /* Check to see if the mechanism is usable before we offer it */
668 while (mech < gss_supported->count && !ok) { 746 while (mech < gss_supported->count && !ok) {
669 /* My DER encoding requires length<128 */ 747 /* My DER encoding requires length<128 */
670 if (gss_supported->elements[mech].length < 128 && 748 if (gss_supported->elements[mech].length < 128 &&
671 ssh_gssapi_check_mechanism(&gssctxt, 749 ssh_gssapi_check_mechanism(&gssctxt,
672 &gss_supported->elements[mech], authctxt->host)) { 750 &gss_supported->elements[mech], gss_host,
751 options.gss_client_identity)) {
673 ok = 1; /* Mechanism works */ 752 ok = 1; /* Mechanism works */
674 } else { 753 } else {
675 mech++; 754 mech++;
676 } 755 }
677 } 756 }
678 757
758 free(gss_host);
759
679 if (!ok) 760 if (!ok)
680 return 0; 761 return 0;
681 762
@@ -906,6 +987,54 @@ input_gssapi_error(int type, u_int32_t plen, struct ssh *ssh)
906 free(lang); 987 free(lang);
907 return r; 988 return r;
908} 989}
990
991int
992userauth_gsskeyex(Authctxt *authctxt)
993{
994 struct ssh *ssh = active_state; /* XXX */
995 struct sshbuf *b;
996 gss_buffer_desc gssbuf;
997 gss_buffer_desc mic = GSS_C_EMPTY_BUFFER;
998 OM_uint32 ms;
999 int r;
1000
1001 static int attempt = 0;
1002 if (attempt++ >= 1)
1003 return (0);
1004
1005 if (gss_kex_context == NULL) {
1006 debug("No valid Key exchange context");
1007 return (0);
1008 }
1009
1010 if ((b = sshbuf_new()) == NULL)
1011 fatal("%s: sshbuf_new failed", __func__);
1012 ssh_gssapi_buildmic(b, authctxt->server_user, authctxt->service,
1013 "gssapi-keyex");
1014
1015 if ((gssbuf.value = sshbuf_mutable_ptr(b)) == NULL)
1016 fatal("%s: sshbuf_mutable_ptr failed", __func__);
1017 gssbuf.length = sshbuf_len(b);
1018
1019 if (GSS_ERROR(ssh_gssapi_sign(gss_kex_context, &gssbuf, &mic))) {
1020 sshbuf_free(b);
1021 return (0);
1022 }
1023
1024 if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_REQUEST)) != 0 ||
1025 (r = sshpkt_put_cstring(ssh, authctxt->server_user)) != 0 ||
1026 (r = sshpkt_put_cstring(ssh, authctxt->service)) != 0 ||
1027 (r = sshpkt_put_cstring(ssh, authctxt->method->name)) != 0 ||
1028 (r = sshpkt_put_string(ssh, mic.value, mic.length)) != 0 ||
1029 (r = sshpkt_send(ssh)) != 0)
1030 fatal("%s: %s", __func__, ssh_err(r));
1031
1032 sshbuf_free(b);
1033 gss_release_buffer(&ms, &mic);
1034
1035 return (1);
1036}
1037
909#endif /* GSSAPI */ 1038#endif /* GSSAPI */
910 1039
911int 1040int