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>2015-11-29 17:36:18 +0000
commit09c4d9b7d41ab3c9973f07e0109e931f57c59c43 (patch)
tree238d7d86bfd8c0080d01fb55cef2ad37df46bd2e /sshconnect2.c
parent651211fd4a199b299540c00c54a46e27fadb04be (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: 2015-11-29 Patch-Name: gssapi.patch
Diffstat (limited to 'sshconnect2.c')
-rw-r--r--sshconnect2.c124
1 files changed, 120 insertions, 4 deletions
diff --git a/sshconnect2.c b/sshconnect2.c
index 775103185..e2ea82656 100644
--- a/sshconnect2.c
+++ b/sshconnect2.c
@@ -160,9 +160,34 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port)
160 struct kex *kex; 160 struct kex *kex;
161 int r; 161 int r;
162 162
163#ifdef GSSAPI
164 char *orig = NULL, *gss = NULL;
165 char *gss_host = NULL;
166#endif
167
163 xxx_host = host; 168 xxx_host = host;
164 xxx_hostaddr = hostaddr; 169 xxx_hostaddr = hostaddr;
165 170
171#ifdef GSSAPI
172 if (options.gss_keyex) {
173 /* Add the GSSAPI mechanisms currently supported on this
174 * client to the key exchange algorithm proposal */
175 orig = myproposal[PROPOSAL_KEX_ALGS];
176
177 if (options.gss_trust_dns)
178 gss_host = (char *)get_canonical_hostname(1);
179 else
180 gss_host = host;
181
182 gss = ssh_gssapi_client_mechanisms(gss_host, options.gss_client_identity);
183 if (gss) {
184 debug("Offering GSSAPI proposal: %s", gss);
185 xasprintf(&myproposal[PROPOSAL_KEX_ALGS],
186 "%s,%s", gss, orig);
187 }
188 }
189#endif
190
166 myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal( 191 myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal(
167 options.kex_algorithms); 192 options.kex_algorithms);
168 myproposal[PROPOSAL_ENC_ALGS_CTOS] = 193 myproposal[PROPOSAL_ENC_ALGS_CTOS] =
@@ -193,6 +218,17 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port)
193 order_hostkeyalgs(host, hostaddr, port)); 218 order_hostkeyalgs(host, hostaddr, port));
194 } 219 }
195 220
221#ifdef GSSAPI
222 /* If we've got GSSAPI algorithms, then we also support the
223 * 'null' hostkey, as a last resort */
224 if (options.gss_keyex && gss) {
225 orig = myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS];
226 xasprintf(&myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS],
227 "%s,null", orig);
228 free(gss);
229 }
230#endif
231
196 if (options.rekey_limit || options.rekey_interval) 232 if (options.rekey_limit || options.rekey_interval)
197 packet_set_rekey_limits((u_int32_t)options.rekey_limit, 233 packet_set_rekey_limits((u_int32_t)options.rekey_limit,
198 (time_t)options.rekey_interval); 234 (time_t)options.rekey_interval);
@@ -211,10 +247,30 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port)
211# endif 247# endif
212#endif 248#endif
213 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
214 kex->client_version_string=client_version_string; 257 kex->client_version_string=client_version_string;
215 kex->server_version_string=server_version_string; 258 kex->server_version_string=server_version_string;
216 kex->verify_host_key=&verify_host_key_callback; 259 kex->verify_host_key=&verify_host_key_callback;
217 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 if (options.gss_server_identity) {
267 kex->gss_host = options.gss_server_identity;
268 } else {
269 kex->gss_host = gss_host;
270 }
271 }
272#endif
273
218 dispatch_run(DISPATCH_BLOCK, &kex->done, active_state); 274 dispatch_run(DISPATCH_BLOCK, &kex->done, active_state);
219 275
220 if (options.use_roaming && !kex->roaming) { 276 if (options.use_roaming && !kex->roaming) {
@@ -306,6 +362,7 @@ int input_gssapi_token(int type, u_int32_t, void *);
306int input_gssapi_hash(int type, u_int32_t, void *); 362int input_gssapi_hash(int type, u_int32_t, void *);
307int input_gssapi_error(int, u_int32_t, void *); 363int input_gssapi_error(int, u_int32_t, void *);
308int input_gssapi_errtok(int, u_int32_t, void *); 364int input_gssapi_errtok(int, u_int32_t, void *);
365int userauth_gsskeyex(Authctxt *authctxt);
309#endif 366#endif
310 367
311void userauth(Authctxt *, char *); 368void userauth(Authctxt *, char *);
@@ -321,6 +378,11 @@ static char *authmethods_get(void);
321 378
322Authmethod authmethods[] = { 379Authmethod authmethods[] = {
323#ifdef GSSAPI 380#ifdef GSSAPI
381 {"gssapi-keyex",
382 userauth_gsskeyex,
383 NULL,
384 &options.gss_authentication,
385 NULL},
324 {"gssapi-with-mic", 386 {"gssapi-with-mic",
325 userauth_gssapi, 387 userauth_gssapi,
326 NULL, 388 NULL,
@@ -627,19 +689,31 @@ userauth_gssapi(Authctxt *authctxt)
627 static u_int mech = 0; 689 static u_int mech = 0;
628 OM_uint32 min; 690 OM_uint32 min;
629 int ok = 0; 691 int ok = 0;
692 const char *gss_host;
693
694 if (options.gss_server_identity)
695 gss_host = options.gss_server_identity;
696 else if (options.gss_trust_dns)
697 gss_host = get_canonical_hostname(1);
698 else
699 gss_host = authctxt->host;
630 700
631 /* Try one GSSAPI method at a time, rather than sending them all at 701 /* Try one GSSAPI method at a time, rather than sending them all at
632 * once. */ 702 * once. */
633 703
634 if (gss_supported == NULL) 704 if (gss_supported == NULL)
635 gss_indicate_mechs(&min, &gss_supported); 705 if (GSS_ERROR(gss_indicate_mechs(&min, &gss_supported))) {
706 gss_supported = NULL;
707 return 0;
708 }
636 709
637 /* Check to see if the mechanism is usable before we offer it */ 710 /* Check to see if the mechanism is usable before we offer it */
638 while (mech < gss_supported->count && !ok) { 711 while (mech < gss_supported->count && !ok) {
639 /* My DER encoding requires length<128 */ 712 /* My DER encoding requires length<128 */
640 if (gss_supported->elements[mech].length < 128 && 713 if (gss_supported->elements[mech].length < 128 &&
641 ssh_gssapi_check_mechanism(&gssctxt, 714 ssh_gssapi_check_mechanism(&gssctxt,
642 &gss_supported->elements[mech], authctxt->host)) { 715 &gss_supported->elements[mech], gss_host,
716 options.gss_client_identity)) {
643 ok = 1; /* Mechanism works */ 717 ok = 1; /* Mechanism works */
644 } else { 718 } else {
645 mech++; 719 mech++;
@@ -736,8 +810,8 @@ input_gssapi_response(int type, u_int32_t plen, void *ctxt)
736{ 810{
737 Authctxt *authctxt = ctxt; 811 Authctxt *authctxt = ctxt;
738 Gssctxt *gssctxt; 812 Gssctxt *gssctxt;
739 int oidlen; 813 u_int oidlen;
740 char *oidv; 814 u_char *oidv;
741 815
742 if (authctxt == NULL) 816 if (authctxt == NULL)
743 fatal("input_gssapi_response: no authentication context"); 817 fatal("input_gssapi_response: no authentication context");
@@ -850,6 +924,48 @@ input_gssapi_error(int type, u_int32_t plen, void *ctxt)
850 free(lang); 924 free(lang);
851 return 0; 925 return 0;
852} 926}
927
928int
929userauth_gsskeyex(Authctxt *authctxt)
930{
931 Buffer b;
932 gss_buffer_desc gssbuf;
933 gss_buffer_desc mic = GSS_C_EMPTY_BUFFER;
934 OM_uint32 ms;
935
936 static int attempt = 0;
937 if (attempt++ >= 1)
938 return (0);
939
940 if (gss_kex_context == NULL) {
941 debug("No valid Key exchange context");
942 return (0);
943 }
944
945 ssh_gssapi_buildmic(&b, authctxt->server_user, authctxt->service,
946 "gssapi-keyex");
947
948 gssbuf.value = buffer_ptr(&b);
949 gssbuf.length = buffer_len(&b);
950
951 if (GSS_ERROR(ssh_gssapi_sign(gss_kex_context, &gssbuf, &mic))) {
952 buffer_free(&b);
953 return (0);
954 }
955
956 packet_start(SSH2_MSG_USERAUTH_REQUEST);
957 packet_put_cstring(authctxt->server_user);
958 packet_put_cstring(authctxt->service);
959 packet_put_cstring(authctxt->method->name);
960 packet_put_string(mic.value, mic.length);
961 packet_send();
962
963 buffer_free(&b);
964 gss_release_buffer(&ms, &mic);
965
966 return (1);
967}
968
853#endif /* GSSAPI */ 969#endif /* GSSAPI */
854 970
855int 971int