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-10-20 22:54:00 +0100
commit72b1d308e6400194ef6e4e7dd45bfa48fa39b5e6 (patch)
tree2a3b57ae5446f4273804064ccc42659adfc2a3b2 /sshconnect2.c
parent3d246f10429fc9a37b98eabef94fe8dc7c61002b (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-10-20 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 1675f3935..8c872a4fb 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,
@@ -686,25 +752,40 @@ userauth_gssapi(Authctxt *authctxt)
686 static u_int mech = 0; 752 static u_int mech = 0;
687 OM_uint32 min; 753 OM_uint32 min;
688 int r, ok = 0; 754 int r, ok = 0;
755 char *gss_host;
756
757 if (options.gss_server_identity)
758 gss_host = xstrdup(options.gss_server_identity);
759 else if (options.gss_trust_dns)
760 gss_host = remote_hostname(active_state);
761 else
762 gss_host = xstrdup(authctxt->host);
689 763
690 /* Try one GSSAPI method at a time, rather than sending them all at 764 /* Try one GSSAPI method at a time, rather than sending them all at
691 * once. */ 765 * once. */
692 766
693 if (gss_supported == NULL) 767 if (gss_supported == NULL)
694 gss_indicate_mechs(&min, &gss_supported); 768 if (GSS_ERROR(gss_indicate_mechs(&min, &gss_supported))) {
769 gss_supported = NULL;
770 free(gss_host);
771 return 0;
772 }
695 773
696 /* Check to see if the mechanism is usable before we offer it */ 774 /* Check to see if the mechanism is usable before we offer it */
697 while (mech < gss_supported->count && !ok) { 775 while (mech < gss_supported->count && !ok) {
698 /* My DER encoding requires length<128 */ 776 /* My DER encoding requires length<128 */
699 if (gss_supported->elements[mech].length < 128 && 777 if (gss_supported->elements[mech].length < 128 &&
700 ssh_gssapi_check_mechanism(&gssctxt, 778 ssh_gssapi_check_mechanism(&gssctxt,
701 &gss_supported->elements[mech], authctxt->host)) { 779 &gss_supported->elements[mech], gss_host,
780 options.gss_client_identity)) {
702 ok = 1; /* Mechanism works */ 781 ok = 1; /* Mechanism works */
703 } else { 782 } else {
704 mech++; 783 mech++;
705 } 784 }
706 } 785 }
707 786
787 free(gss_host);
788
708 if (!ok) 789 if (!ok)
709 return 0; 790 return 0;
710 791
@@ -935,6 +1016,54 @@ input_gssapi_error(int type, u_int32_t plen, struct ssh *ssh)
935 free(lang); 1016 free(lang);
936 return r; 1017 return r;
937} 1018}
1019
1020int
1021userauth_gsskeyex(Authctxt *authctxt)
1022{
1023 struct ssh *ssh = active_state; /* XXX */
1024 struct sshbuf *b;
1025 gss_buffer_desc gssbuf;
1026 gss_buffer_desc mic = GSS_C_EMPTY_BUFFER;
1027 OM_uint32 ms;
1028 int r;
1029
1030 static int attempt = 0;
1031 if (attempt++ >= 1)
1032 return (0);
1033
1034 if (gss_kex_context == NULL) {
1035 debug("No valid Key exchange context");
1036 return (0);
1037 }
1038
1039 if ((b = sshbuf_new()) == NULL)
1040 fatal("%s: sshbuf_new failed", __func__);
1041 ssh_gssapi_buildmic(b, authctxt->server_user, authctxt->service,
1042 "gssapi-keyex");
1043
1044 if ((gssbuf.value = sshbuf_mutable_ptr(b)) == NULL)
1045 fatal("%s: sshbuf_mutable_ptr failed", __func__);
1046 gssbuf.length = sshbuf_len(b);
1047
1048 if (GSS_ERROR(ssh_gssapi_sign(gss_kex_context, &gssbuf, &mic))) {
1049 sshbuf_free(b);
1050 return (0);
1051 }
1052
1053 if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_REQUEST)) != 0 ||
1054 (r = sshpkt_put_cstring(ssh, authctxt->server_user)) != 0 ||
1055 (r = sshpkt_put_cstring(ssh, authctxt->service)) != 0 ||
1056 (r = sshpkt_put_cstring(ssh, authctxt->method->name)) != 0 ||
1057 (r = sshpkt_put_string(ssh, mic.value, mic.length)) != 0 ||
1058 (r = sshpkt_send(ssh)) != 0)
1059 fatal("%s: %s", __func__, ssh_err(r));
1060
1061 sshbuf_free(b);
1062 gss_release_buffer(&ms, &mic);
1063
1064 return (1);
1065}
1066
938#endif /* GSSAPI */ 1067#endif /* GSSAPI */
939 1068
940int 1069int