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>2019-06-05 07:06:44 +0100
commit7ce79be85036c4b36937f1b1ba85f6094068412c (patch)
treec964917d8395ef5605cff9513aad4458b222beae /sshconnect2.c
parent102062f825fb26a74295a1c089c00c4c4c76b68a (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. Origin: other, https://github.com/openssh-gsskex/openssh-gsskex/commits/debian/master Bug: https://bugzilla.mindrot.org/show_bug.cgi?id=1242 Last-Updated: 2019-06-05 Patch-Name: gssapi.patch
Diffstat (limited to 'sshconnect2.c')
-rw-r--r--sshconnect2.c140
1 files changed, 136 insertions, 4 deletions
diff --git a/sshconnect2.c b/sshconnect2.c
index dffee90b1..4020371ae 100644
--- a/sshconnect2.c
+++ b/sshconnect2.c
@@ -78,8 +78,6 @@
78#endif 78#endif
79 79
80/* import */ 80/* import */
81extern char *client_version_string;
82extern char *server_version_string;
83extern Options options; 81extern Options options;
84 82
85/* 83/*
@@ -161,6 +159,11 @@ ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port)
161 char *s, *all_key; 159 char *s, *all_key;
162 int r; 160 int r;
163 161
162#if defined(GSSAPI) && defined(WITH_OPENSSL)
163 char *orig = NULL, *gss = NULL;
164 char *gss_host = NULL;
165#endif
166
164 xxx_host = host; 167 xxx_host = host;
165 xxx_hostaddr = hostaddr; 168 xxx_hostaddr = hostaddr;
166 169
@@ -193,6 +196,35 @@ ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port)
193 order_hostkeyalgs(host, hostaddr, port)); 196 order_hostkeyalgs(host, hostaddr, port));
194 } 197 }
195 198
199#if defined(GSSAPI) && defined(WITH_OPENSSL)
200 if (options.gss_keyex) {
201 /* Add the GSSAPI mechanisms currently supported on this
202 * client to the key exchange algorithm proposal */
203 orig = myproposal[PROPOSAL_KEX_ALGS];
204
205 if (options.gss_server_identity)
206 gss_host = xstrdup(options.gss_server_identity);
207 else if (options.gss_trust_dns)
208 gss_host = remote_hostname(ssh);
209 else
210 gss_host = xstrdup(host);
211
212 gss = ssh_gssapi_client_mechanisms(gss_host,
213 options.gss_client_identity, options.gss_kex_algorithms);
214 if (gss) {
215 debug("Offering GSSAPI proposal: %s", gss);
216 xasprintf(&myproposal[PROPOSAL_KEX_ALGS],
217 "%s,%s", gss, orig);
218
219 /* If we've got GSSAPI algorithms, then we also support the
220 * 'null' hostkey, as a last resort */
221 orig = myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS];
222 xasprintf(&myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS],
223 "%s,null", orig);
224 }
225 }
226#endif
227
196 if (options.rekey_limit || options.rekey_interval) 228 if (options.rekey_limit || options.rekey_interval)
197 ssh_packet_set_rekey_limits(ssh, options.rekey_limit, 229 ssh_packet_set_rekey_limits(ssh, options.rekey_limit,
198 options.rekey_interval); 230 options.rekey_interval);
@@ -211,16 +243,46 @@ ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port)
211# ifdef OPENSSL_HAS_ECC 243# ifdef OPENSSL_HAS_ECC
212 ssh->kex->kex[KEX_ECDH_SHA2] = kex_gen_client; 244 ssh->kex->kex[KEX_ECDH_SHA2] = kex_gen_client;
213# endif 245# endif
246# ifdef GSSAPI
247 if (options.gss_keyex) {
248 ssh->kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_client;
249 ssh->kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_client;
250 ssh->kex->kex[KEX_GSS_GRP14_SHA256] = kexgss_client;
251 ssh->kex->kex[KEX_GSS_GRP16_SHA512] = kexgss_client;
252 ssh->kex->kex[KEX_GSS_GEX_SHA1] = kexgssgex_client;
253 ssh->kex->kex[KEX_GSS_NISTP256_SHA256] = kexgss_client;
254 ssh->kex->kex[KEX_GSS_C25519_SHA256] = kexgss_client;
255 }
256# endif
214#endif 257#endif
215 ssh->kex->kex[KEX_C25519_SHA256] = kex_gen_client; 258 ssh->kex->kex[KEX_C25519_SHA256] = kex_gen_client;
216 ssh->kex->kex[KEX_KEM_SNTRUP4591761X25519_SHA512] = kex_gen_client; 259 ssh->kex->kex[KEX_KEM_SNTRUP4591761X25519_SHA512] = kex_gen_client;
217 ssh->kex->verify_host_key=&verify_host_key_callback; 260 ssh->kex->verify_host_key=&verify_host_key_callback;
218 261
262#if defined(GSSAPI) && defined(WITH_OPENSSL)
263 if (options.gss_keyex) {
264 ssh->kex->gss_deleg_creds = options.gss_deleg_creds;
265 ssh->kex->gss_trust_dns = options.gss_trust_dns;
266 ssh->kex->gss_client = options.gss_client_identity;
267 ssh->kex->gss_host = gss_host;
268 }
269#endif
270
219 ssh_dispatch_run_fatal(ssh, DISPATCH_BLOCK, &ssh->kex->done); 271 ssh_dispatch_run_fatal(ssh, DISPATCH_BLOCK, &ssh->kex->done);
220 272
221 /* remove ext-info from the KEX proposals for rekeying */ 273 /* remove ext-info from the KEX proposals for rekeying */
222 myproposal[PROPOSAL_KEX_ALGS] = 274 myproposal[PROPOSAL_KEX_ALGS] =
223 compat_kex_proposal(options.kex_algorithms); 275 compat_kex_proposal(options.kex_algorithms);
276#if defined(GSSAPI) && defined(WITH_OPENSSL)
277 /* repair myproposal after it was crumpled by the */
278 /* ext-info removal above */
279 if (gss) {
280 orig = myproposal[PROPOSAL_KEX_ALGS];
281 xasprintf(&myproposal[PROPOSAL_KEX_ALGS],
282 "%s,%s", gss, orig);
283 free(gss);
284 }
285#endif
224 if ((r = kex_prop2buf(ssh->kex->my, myproposal)) != 0) 286 if ((r = kex_prop2buf(ssh->kex->my, myproposal)) != 0)
225 fatal("kex_prop2buf: %s", ssh_err(r)); 287 fatal("kex_prop2buf: %s", ssh_err(r));
226 288
@@ -317,6 +379,7 @@ static int input_gssapi_response(int type, u_int32_t, struct ssh *);
317static int input_gssapi_token(int type, u_int32_t, struct ssh *); 379static int input_gssapi_token(int type, u_int32_t, struct ssh *);
318static int input_gssapi_error(int, u_int32_t, struct ssh *); 380static int input_gssapi_error(int, u_int32_t, struct ssh *);
319static int input_gssapi_errtok(int, u_int32_t, struct ssh *); 381static int input_gssapi_errtok(int, u_int32_t, struct ssh *);
382static int userauth_gsskeyex(struct ssh *);
320#endif 383#endif
321 384
322void userauth(struct ssh *, char *); 385void userauth(struct ssh *, char *);
@@ -333,6 +396,11 @@ static char *authmethods_get(void);
333 396
334Authmethod authmethods[] = { 397Authmethod authmethods[] = {
335#ifdef GSSAPI 398#ifdef GSSAPI
399 {"gssapi-keyex",
400 userauth_gsskeyex,
401 NULL,
402 &options.gss_keyex,
403 NULL},
336 {"gssapi-with-mic", 404 {"gssapi-with-mic",
337 userauth_gssapi, 405 userauth_gssapi,
338 userauth_gssapi_cleanup, 406 userauth_gssapi_cleanup,
@@ -698,12 +766,25 @@ userauth_gssapi(struct ssh *ssh)
698 OM_uint32 min; 766 OM_uint32 min;
699 int r, ok = 0; 767 int r, ok = 0;
700 gss_OID mech = NULL; 768 gss_OID mech = NULL;
769 char *gss_host;
770
771 if (options.gss_server_identity)
772 gss_host = xstrdup(options.gss_server_identity);
773 else if (options.gss_trust_dns)
774 gss_host = remote_hostname(ssh);
775 else
776 gss_host = xstrdup(authctxt->host);
701 777
702 /* Try one GSSAPI method at a time, rather than sending them all at 778 /* Try one GSSAPI method at a time, rather than sending them all at
703 * once. */ 779 * once. */
704 780
705 if (authctxt->gss_supported_mechs == NULL) 781 if (authctxt->gss_supported_mechs == NULL)
706 gss_indicate_mechs(&min, &authctxt->gss_supported_mechs); 782 if (GSS_ERROR(gss_indicate_mechs(&min,
783 &authctxt->gss_supported_mechs))) {
784 authctxt->gss_supported_mechs = NULL;
785 free(gss_host);
786 return 0;
787 }
707 788
708 /* Check to see whether the mechanism is usable before we offer it */ 789 /* Check to see whether the mechanism is usable before we offer it */
709 while (authctxt->mech_tried < authctxt->gss_supported_mechs->count && 790 while (authctxt->mech_tried < authctxt->gss_supported_mechs->count &&
@@ -712,13 +793,15 @@ userauth_gssapi(struct ssh *ssh)
712 elements[authctxt->mech_tried]; 793 elements[authctxt->mech_tried];
713 /* My DER encoding requires length<128 */ 794 /* My DER encoding requires length<128 */
714 if (mech->length < 128 && ssh_gssapi_check_mechanism(&gssctxt, 795 if (mech->length < 128 && ssh_gssapi_check_mechanism(&gssctxt,
715 mech, authctxt->host)) { 796 mech, gss_host, options.gss_client_identity)) {
716 ok = 1; /* Mechanism works */ 797 ok = 1; /* Mechanism works */
717 } else { 798 } else {
718 authctxt->mech_tried++; 799 authctxt->mech_tried++;
719 } 800 }
720 } 801 }
721 802
803 free(gss_host);
804
722 if (!ok || mech == NULL) 805 if (!ok || mech == NULL)
723 return 0; 806 return 0;
724 807
@@ -958,6 +1041,55 @@ input_gssapi_error(int type, u_int32_t plen, struct ssh *ssh)
958 free(lang); 1041 free(lang);
959 return r; 1042 return r;
960} 1043}
1044
1045int
1046userauth_gsskeyex(struct ssh *ssh)
1047{
1048 struct sshbuf *b = NULL;
1049 Authctxt *authctxt = ssh->authctxt;
1050 gss_buffer_desc gssbuf;
1051 gss_buffer_desc mic = GSS_C_EMPTY_BUFFER;
1052 OM_uint32 ms;
1053 int r;
1054
1055 static int attempt = 0;
1056 if (attempt++ >= 1)
1057 return (0);
1058
1059 if (gss_kex_context == NULL) {
1060 debug("No valid Key exchange context");
1061 return (0);
1062 }
1063
1064 if ((b = sshbuf_new()) == NULL)
1065 fatal("%s: sshbuf_new failed", __func__);
1066
1067 ssh_gssapi_buildmic(b, authctxt->server_user, authctxt->service,
1068 "gssapi-keyex");
1069
1070 if ((gssbuf.value = sshbuf_mutable_ptr(b)) == NULL)
1071 fatal("%s: sshbuf_mutable_ptr failed", __func__);
1072 gssbuf.length = sshbuf_len(b);
1073
1074 if (GSS_ERROR(ssh_gssapi_sign(gss_kex_context, &gssbuf, &mic))) {
1075 sshbuf_free(b);
1076 return (0);
1077 }
1078
1079 if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_REQUEST)) != 0 ||
1080 (r = sshpkt_put_cstring(ssh, authctxt->server_user)) != 0 ||
1081 (r = sshpkt_put_cstring(ssh, authctxt->service)) != 0 ||
1082 (r = sshpkt_put_cstring(ssh, authctxt->method->name)) != 0 ||
1083 (r = sshpkt_put_string(ssh, mic.value, mic.length)) != 0 ||
1084 (r = sshpkt_send(ssh)) != 0)
1085 fatal("%s: %s", __func__, ssh_err(r));
1086
1087 sshbuf_free(b);
1088 gss_release_buffer(&ms, &mic);
1089
1090 return (1);
1091}
1092
961#endif /* GSSAPI */ 1093#endif /* GSSAPI */
962 1094
963static int 1095static int