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>2020-02-21 12:01:36 +0000
commit34aff3aa136e5a65f441b25811dd466488fda087 (patch)
treee2170faeed03d67545255d3d3c9d62280414c0b2 /sshconnect2.c
parentf0de78bd4f29fa688c5df116f3f9cd43543a76d0 (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: 2020-02-21 Patch-Name: gssapi.patch
Diffstat (limited to 'sshconnect2.c')
-rw-r--r--sshconnect2.c142
1 files changed, 137 insertions, 5 deletions
diff --git a/sshconnect2.c b/sshconnect2.c
index af00fb30c..03bc87eb4 100644
--- a/sshconnect2.c
+++ b/sshconnect2.c
@@ -80,8 +80,6 @@
80#endif 80#endif
81 81
82/* import */ 82/* import */
83extern char *client_version_string;
84extern char *server_version_string;
85extern Options options; 83extern Options options;
86 84
87/* 85/*
@@ -163,6 +161,11 @@ ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port)
163 char *s, *all_key; 161 char *s, *all_key;
164 int r, use_known_hosts_order = 0; 162 int r, use_known_hosts_order = 0;
165 163
164#if defined(GSSAPI) && defined(WITH_OPENSSL)
165 char *orig = NULL, *gss = NULL;
166 char *gss_host = NULL;
167#endif
168
166 xxx_host = host; 169 xxx_host = host;
167 xxx_hostaddr = hostaddr; 170 xxx_hostaddr = hostaddr;
168 171
@@ -206,6 +209,35 @@ ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port)
206 compat_pkalg_proposal(options.hostkeyalgorithms); 209 compat_pkalg_proposal(options.hostkeyalgorithms);
207 } 210 }
208 211
212#if defined(GSSAPI) && defined(WITH_OPENSSL)
213 if (options.gss_keyex) {
214 /* Add the GSSAPI mechanisms currently supported on this
215 * client to the key exchange algorithm proposal */
216 orig = myproposal[PROPOSAL_KEX_ALGS];
217
218 if (options.gss_server_identity)
219 gss_host = xstrdup(options.gss_server_identity);
220 else if (options.gss_trust_dns)
221 gss_host = remote_hostname(ssh);
222 else
223 gss_host = xstrdup(host);
224
225 gss = ssh_gssapi_client_mechanisms(gss_host,
226 options.gss_client_identity, options.gss_kex_algorithms);
227 if (gss) {
228 debug("Offering GSSAPI proposal: %s", gss);
229 xasprintf(&myproposal[PROPOSAL_KEX_ALGS],
230 "%s,%s", gss, orig);
231
232 /* If we've got GSSAPI algorithms, then we also support the
233 * 'null' hostkey, as a last resort */
234 orig = myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS];
235 xasprintf(&myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS],
236 "%s,null", orig);
237 }
238 }
239#endif
240
209 if (options.rekey_limit || options.rekey_interval) 241 if (options.rekey_limit || options.rekey_interval)
210 ssh_packet_set_rekey_limits(ssh, options.rekey_limit, 242 ssh_packet_set_rekey_limits(ssh, options.rekey_limit,
211 options.rekey_interval); 243 options.rekey_interval);
@@ -224,16 +256,46 @@ ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port)
224# ifdef OPENSSL_HAS_ECC 256# ifdef OPENSSL_HAS_ECC
225 ssh->kex->kex[KEX_ECDH_SHA2] = kex_gen_client; 257 ssh->kex->kex[KEX_ECDH_SHA2] = kex_gen_client;
226# endif 258# endif
227#endif 259# ifdef GSSAPI
260 if (options.gss_keyex) {
261 ssh->kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_client;
262 ssh->kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_client;
263 ssh->kex->kex[KEX_GSS_GRP14_SHA256] = kexgss_client;
264 ssh->kex->kex[KEX_GSS_GRP16_SHA512] = kexgss_client;
265 ssh->kex->kex[KEX_GSS_GEX_SHA1] = kexgssgex_client;
266 ssh->kex->kex[KEX_GSS_NISTP256_SHA256] = kexgss_client;
267 ssh->kex->kex[KEX_GSS_C25519_SHA256] = kexgss_client;
268 }
269# endif
270#endif /* WITH_OPENSSL */
228 ssh->kex->kex[KEX_C25519_SHA256] = kex_gen_client; 271 ssh->kex->kex[KEX_C25519_SHA256] = kex_gen_client;
229 ssh->kex->kex[KEX_KEM_SNTRUP4591761X25519_SHA512] = kex_gen_client; 272 ssh->kex->kex[KEX_KEM_SNTRUP4591761X25519_SHA512] = kex_gen_client;
230 ssh->kex->verify_host_key=&verify_host_key_callback; 273 ssh->kex->verify_host_key=&verify_host_key_callback;
231 274
275#if defined(GSSAPI) && defined(WITH_OPENSSL)
276 if (options.gss_keyex) {
277 ssh->kex->gss_deleg_creds = options.gss_deleg_creds;
278 ssh->kex->gss_trust_dns = options.gss_trust_dns;
279 ssh->kex->gss_client = options.gss_client_identity;
280 ssh->kex->gss_host = gss_host;
281 }
282#endif
283
232 ssh_dispatch_run_fatal(ssh, DISPATCH_BLOCK, &ssh->kex->done); 284 ssh_dispatch_run_fatal(ssh, DISPATCH_BLOCK, &ssh->kex->done);
233 285
234 /* remove ext-info from the KEX proposals for rekeying */ 286 /* remove ext-info from the KEX proposals for rekeying */
235 myproposal[PROPOSAL_KEX_ALGS] = 287 myproposal[PROPOSAL_KEX_ALGS] =
236 compat_kex_proposal(options.kex_algorithms); 288 compat_kex_proposal(options.kex_algorithms);
289#if defined(GSSAPI) && defined(WITH_OPENSSL)
290 /* repair myproposal after it was crumpled by the */
291 /* ext-info removal above */
292 if (gss) {
293 orig = myproposal[PROPOSAL_KEX_ALGS];
294 xasprintf(&myproposal[PROPOSAL_KEX_ALGS],
295 "%s,%s", gss, orig);
296 free(gss);
297 }
298#endif
237 if ((r = kex_prop2buf(ssh->kex->my, myproposal)) != 0) 299 if ((r = kex_prop2buf(ssh->kex->my, myproposal)) != 0)
238 fatal("kex_prop2buf: %s", ssh_err(r)); 300 fatal("kex_prop2buf: %s", ssh_err(r));
239 301
@@ -330,6 +392,7 @@ static int input_gssapi_response(int type, u_int32_t, struct ssh *);
330static int input_gssapi_token(int type, u_int32_t, struct ssh *); 392static int input_gssapi_token(int type, u_int32_t, struct ssh *);
331static int input_gssapi_error(int, u_int32_t, struct ssh *); 393static int input_gssapi_error(int, u_int32_t, struct ssh *);
332static int input_gssapi_errtok(int, u_int32_t, struct ssh *); 394static int input_gssapi_errtok(int, u_int32_t, struct ssh *);
395static int userauth_gsskeyex(struct ssh *);
333#endif 396#endif
334 397
335void userauth(struct ssh *, char *); 398void userauth(struct ssh *, char *);
@@ -346,6 +409,11 @@ static char *authmethods_get(void);
346 409
347Authmethod authmethods[] = { 410Authmethod authmethods[] = {
348#ifdef GSSAPI 411#ifdef GSSAPI
412 {"gssapi-keyex",
413 userauth_gsskeyex,
414 NULL,
415 &options.gss_keyex,
416 NULL},
349 {"gssapi-with-mic", 417 {"gssapi-with-mic",
350 userauth_gssapi, 418 userauth_gssapi,
351 userauth_gssapi_cleanup, 419 userauth_gssapi_cleanup,
@@ -716,12 +784,25 @@ userauth_gssapi(struct ssh *ssh)
716 OM_uint32 min; 784 OM_uint32 min;
717 int r, ok = 0; 785 int r, ok = 0;
718 gss_OID mech = NULL; 786 gss_OID mech = NULL;
787 char *gss_host;
788
789 if (options.gss_server_identity)
790 gss_host = xstrdup(options.gss_server_identity);
791 else if (options.gss_trust_dns)
792 gss_host = remote_hostname(ssh);
793 else
794 gss_host = xstrdup(authctxt->host);
719 795
720 /* Try one GSSAPI method at a time, rather than sending them all at 796 /* Try one GSSAPI method at a time, rather than sending them all at
721 * once. */ 797 * once. */
722 798
723 if (authctxt->gss_supported_mechs == NULL) 799 if (authctxt->gss_supported_mechs == NULL)
724 gss_indicate_mechs(&min, &authctxt->gss_supported_mechs); 800 if (GSS_ERROR(gss_indicate_mechs(&min,
801 &authctxt->gss_supported_mechs))) {
802 authctxt->gss_supported_mechs = NULL;
803 free(gss_host);
804 return 0;
805 }
725 806
726 /* Check to see whether the mechanism is usable before we offer it */ 807 /* Check to see whether the mechanism is usable before we offer it */
727 while (authctxt->mech_tried < authctxt->gss_supported_mechs->count && 808 while (authctxt->mech_tried < authctxt->gss_supported_mechs->count &&
@@ -730,13 +811,15 @@ userauth_gssapi(struct ssh *ssh)
730 elements[authctxt->mech_tried]; 811 elements[authctxt->mech_tried];
731 /* My DER encoding requires length<128 */ 812 /* My DER encoding requires length<128 */
732 if (mech->length < 128 && ssh_gssapi_check_mechanism(&gssctxt, 813 if (mech->length < 128 && ssh_gssapi_check_mechanism(&gssctxt,
733 mech, authctxt->host)) { 814 mech, gss_host, options.gss_client_identity)) {
734 ok = 1; /* Mechanism works */ 815 ok = 1; /* Mechanism works */
735 } else { 816 } else {
736 authctxt->mech_tried++; 817 authctxt->mech_tried++;
737 } 818 }
738 } 819 }
739 820
821 free(gss_host);
822
740 if (!ok || mech == NULL) 823 if (!ok || mech == NULL)
741 return 0; 824 return 0;
742 825
@@ -976,6 +1059,55 @@ input_gssapi_error(int type, u_int32_t plen, struct ssh *ssh)
976 free(lang); 1059 free(lang);
977 return r; 1060 return r;
978} 1061}
1062
1063int
1064userauth_gsskeyex(struct ssh *ssh)
1065{
1066 struct sshbuf *b = NULL;
1067 Authctxt *authctxt = ssh->authctxt;
1068 gss_buffer_desc gssbuf;
1069 gss_buffer_desc mic = GSS_C_EMPTY_BUFFER;
1070 OM_uint32 ms;
1071 int r;
1072
1073 static int attempt = 0;
1074 if (attempt++ >= 1)
1075 return (0);
1076
1077 if (gss_kex_context == NULL) {
1078 debug("No valid Key exchange context");
1079 return (0);
1080 }
1081
1082 if ((b = sshbuf_new()) == NULL)
1083 fatal("%s: sshbuf_new failed", __func__);
1084
1085 ssh_gssapi_buildmic(b, authctxt->server_user, authctxt->service,
1086 "gssapi-keyex");
1087
1088 if ((gssbuf.value = sshbuf_mutable_ptr(b)) == NULL)
1089 fatal("%s: sshbuf_mutable_ptr failed", __func__);
1090 gssbuf.length = sshbuf_len(b);
1091
1092 if (GSS_ERROR(ssh_gssapi_sign(gss_kex_context, &gssbuf, &mic))) {
1093 sshbuf_free(b);
1094 return (0);
1095 }
1096
1097 if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_REQUEST)) != 0 ||
1098 (r = sshpkt_put_cstring(ssh, authctxt->server_user)) != 0 ||
1099 (r = sshpkt_put_cstring(ssh, authctxt->service)) != 0 ||
1100 (r = sshpkt_put_cstring(ssh, authctxt->method->name)) != 0 ||
1101 (r = sshpkt_put_string(ssh, mic.value, mic.length)) != 0 ||
1102 (r = sshpkt_send(ssh)) != 0)
1103 fatal("%s: %s", __func__, ssh_err(r));
1104
1105 sshbuf_free(b);
1106 gss_release_buffer(&ms, &mic);
1107
1108 return (1);
1109}
1110
979#endif /* GSSAPI */ 1111#endif /* GSSAPI */
980 1112
981static int 1113static int