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-10-04 13:54:43 +0100
commit4e70490950e5c5134df48848affaf73685bf0284 (patch)
tree59de097e770693fb1f81268e85f7802df32cb58e /sshconnect2.c
parent62f54f20bf351468e0124f63cc2902ee40d9b0e9 (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-10-04 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 be9397e48..c22477f59 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(options.rekey_limit, 230 packet_set_rekey_limits(options.rekey_limit,
197 options.rekey_interval); 231 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 ssh_dispatch_run_fatal(active_state, DISPATCH_BLOCK, &kex->done); 270 ssh_dispatch_run_fatal(active_state, DISPATCH_BLOCK, &kex->done);
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, struct ssh *);
311int input_gssapi_hash(int type, u_int32_t, struct ssh *); 371int input_gssapi_hash(int type, u_int32_t, struct ssh *);
312int input_gssapi_error(int, u_int32_t, struct ssh *); 372int input_gssapi_error(int, u_int32_t, struct ssh *);
313int input_gssapi_errtok(int, u_int32_t, struct ssh *); 373int input_gssapi_errtok(int, u_int32_t, struct ssh *);
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,
@@ -654,25 +720,40 @@ userauth_gssapi(Authctxt *authctxt)
654 static u_int mech = 0; 720 static u_int mech = 0;
655 OM_uint32 min; 721 OM_uint32 min;
656 int ok = 0; 722 int ok = 0;
723 char *gss_host;
724
725 if (options.gss_server_identity)
726 gss_host = xstrdup(options.gss_server_identity);
727 else if (options.gss_trust_dns)
728 gss_host = remote_hostname(active_state);
729 else
730 gss_host = xstrdup(authctxt->host);
657 731
658 /* Try one GSSAPI method at a time, rather than sending them all at 732 /* Try one GSSAPI method at a time, rather than sending them all at
659 * once. */ 733 * once. */
660 734
661 if (gss_supported == NULL) 735 if (gss_supported == NULL)
662 gss_indicate_mechs(&min, &gss_supported); 736 if (GSS_ERROR(gss_indicate_mechs(&min, &gss_supported))) {
737 gss_supported = NULL;
738 free(gss_host);
739 return 0;
740 }
663 741
664 /* Check to see if the mechanism is usable before we offer it */ 742 /* Check to see if the mechanism is usable before we offer it */
665 while (mech < gss_supported->count && !ok) { 743 while (mech < gss_supported->count && !ok) {
666 /* My DER encoding requires length<128 */ 744 /* My DER encoding requires length<128 */
667 if (gss_supported->elements[mech].length < 128 && 745 if (gss_supported->elements[mech].length < 128 &&
668 ssh_gssapi_check_mechanism(&gssctxt, 746 ssh_gssapi_check_mechanism(&gssctxt,
669 &gss_supported->elements[mech], authctxt->host)) { 747 &gss_supported->elements[mech], gss_host,
748 options.gss_client_identity)) {
670 ok = 1; /* Mechanism works */ 749 ok = 1; /* Mechanism works */
671 } else { 750 } else {
672 mech++; 751 mech++;
673 } 752 }
674 } 753 }
675 754
755 free(gss_host);
756
676 if (!ok) 757 if (!ok)
677 return 0; 758 return 0;
678 759
@@ -763,8 +844,8 @@ input_gssapi_response(int type, u_int32_t plen, struct ssh *ssh)
763{ 844{
764 Authctxt *authctxt = ssh->authctxt; 845 Authctxt *authctxt = ssh->authctxt;
765 Gssctxt *gssctxt; 846 Gssctxt *gssctxt;
766 int oidlen; 847 u_int oidlen;
767 char *oidv; 848 u_char *oidv;
768 849
769 if (authctxt == NULL) 850 if (authctxt == NULL)
770 fatal("input_gssapi_response: no authentication context"); 851 fatal("input_gssapi_response: no authentication context");
@@ -877,6 +958,48 @@ input_gssapi_error(int type, u_int32_t plen, struct ssh *ssh)
877 free(lang); 958 free(lang);
878 return 0; 959 return 0;
879} 960}
961
962int
963userauth_gsskeyex(Authctxt *authctxt)
964{
965 Buffer b;
966 gss_buffer_desc gssbuf;
967 gss_buffer_desc mic = GSS_C_EMPTY_BUFFER;
968 OM_uint32 ms;
969
970 static int attempt = 0;
971 if (attempt++ >= 1)
972 return (0);
973
974 if (gss_kex_context == NULL) {
975 debug("No valid Key exchange context");
976 return (0);
977 }
978
979 ssh_gssapi_buildmic(&b, authctxt->server_user, authctxt->service,
980 "gssapi-keyex");
981
982 gssbuf.value = buffer_ptr(&b);
983 gssbuf.length = buffer_len(&b);
984
985 if (GSS_ERROR(ssh_gssapi_sign(gss_kex_context, &gssbuf, &mic))) {
986 buffer_free(&b);
987 return (0);
988 }
989
990 packet_start(SSH2_MSG_USERAUTH_REQUEST);
991 packet_put_cstring(authctxt->server_user);
992 packet_put_cstring(authctxt->service);
993 packet_put_cstring(authctxt->method->name);
994 packet_put_string(mic.value, mic.length);
995 packet_send();
996
997 buffer_free(&b);
998 gss_release_buffer(&ms, &mic);
999
1000 return (1);
1001}
1002
880#endif /* GSSAPI */ 1003#endif /* GSSAPI */
881 1004
882int 1005int