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>2014-10-07 14:26:43 +0100
commit1c1b6fa17982eb622e2c4e8f4a279f2113f57413 (patch)
treea67e7472f48242904e6a45732508822af63fd331 /sshconnect2.c
parent487bdb3a5ef6075887b830ccb8a0b14f6da78e93 (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: 2014-10-07 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 68f7f4fdd..7b478f16d 100644
--- a/sshconnect2.c
+++ b/sshconnect2.c
@@ -159,9 +159,34 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port)
159 char *myproposal[PROPOSAL_MAX] = { KEX_CLIENT }; 159 char *myproposal[PROPOSAL_MAX] = { KEX_CLIENT };
160 Kex *kex; 160 Kex *kex;
161 161
162#ifdef GSSAPI
163 char *orig = NULL, *gss = NULL;
164 char *gss_host = NULL;
165#endif
166
162 xxx_host = host; 167 xxx_host = host;
163 xxx_hostaddr = hostaddr; 168 xxx_hostaddr = hostaddr;
164 169
170#ifdef GSSAPI
171 if (options.gss_keyex) {
172 /* Add the GSSAPI mechanisms currently supported on this
173 * client to the key exchange algorithm proposal */
174 orig = myproposal[PROPOSAL_KEX_ALGS];
175
176 if (options.gss_trust_dns)
177 gss_host = (char *)get_canonical_hostname(1);
178 else
179 gss_host = host;
180
181 gss = ssh_gssapi_client_mechanisms(gss_host, options.gss_client_identity);
182 if (gss) {
183 debug("Offering GSSAPI proposal: %s", gss);
184 xasprintf(&myproposal[PROPOSAL_KEX_ALGS],
185 "%s,%s", gss, orig);
186 }
187 }
188#endif
189
165 if (options.ciphers == (char *)-1) { 190 if (options.ciphers == (char *)-1) {
166 logit("No valid ciphers for protocol version 2 given, using defaults."); 191 logit("No valid ciphers for protocol version 2 given, using defaults.");
167 options.ciphers = NULL; 192 options.ciphers = NULL;
@@ -199,6 +224,17 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port)
199 myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal( 224 myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal(
200 myproposal[PROPOSAL_KEX_ALGS]); 225 myproposal[PROPOSAL_KEX_ALGS]);
201 226
227#ifdef GSSAPI
228 /* If we've got GSSAPI algorithms, then we also support the
229 * 'null' hostkey, as a last resort */
230 if (options.gss_keyex && gss) {
231 orig = myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS];
232 xasprintf(&myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS],
233 "%s,null", orig);
234 free(gss);
235 }
236#endif
237
202 if (options.rekey_limit || options.rekey_interval) 238 if (options.rekey_limit || options.rekey_interval)
203 packet_set_rekey_limits((u_int32_t)options.rekey_limit, 239 packet_set_rekey_limits((u_int32_t)options.rekey_limit,
204 (time_t)options.rekey_interval); 240 (time_t)options.rekey_interval);
@@ -213,10 +249,30 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port)
213 kex->kex[KEX_ECDH_SHA2] = kexecdh_client; 249 kex->kex[KEX_ECDH_SHA2] = kexecdh_client;
214#endif 250#endif
215 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
216 kex->client_version_string=client_version_string; 259 kex->client_version_string=client_version_string;
217 kex->server_version_string=server_version_string; 260 kex->server_version_string=server_version_string;
218 kex->verify_host_key=&verify_host_key_callback; 261 kex->verify_host_key=&verify_host_key_callback;
219 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 if (options.gss_server_identity) {
269 kex->gss_host = options.gss_server_identity;
270 } else {
271 kex->gss_host = gss_host;
272 }
273 }
274#endif
275
220 xxx_kex = kex; 276 xxx_kex = kex;
221 277
222 dispatch_run(DISPATCH_BLOCK, &kex->done, kex); 278 dispatch_run(DISPATCH_BLOCK, &kex->done, kex);
@@ -306,6 +362,7 @@ void input_gssapi_token(int type, u_int32_t, void *);
306void input_gssapi_hash(int type, u_int32_t, void *); 362void input_gssapi_hash(int type, u_int32_t, void *);
307void input_gssapi_error(int, u_int32_t, void *); 363void input_gssapi_error(int, u_int32_t, void *);
308void input_gssapi_errtok(int, u_int32_t, void *); 364void 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,
@@ -617,19 +679,31 @@ userauth_gssapi(Authctxt *authctxt)
617 static u_int mech = 0; 679 static u_int mech = 0;
618 OM_uint32 min; 680 OM_uint32 min;
619 int ok = 0; 681 int ok = 0;
682 const char *gss_host;
683
684 if (options.gss_server_identity)
685 gss_host = options.gss_server_identity;
686 else if (options.gss_trust_dns)
687 gss_host = get_canonical_hostname(1);
688 else
689 gss_host = authctxt->host;
620 690
621 /* Try one GSSAPI method at a time, rather than sending them all at 691 /* Try one GSSAPI method at a time, rather than sending them all at
622 * once. */ 692 * once. */
623 693
624 if (gss_supported == NULL) 694 if (gss_supported == NULL)
625 gss_indicate_mechs(&min, &gss_supported); 695 if (GSS_ERROR(gss_indicate_mechs(&min, &gss_supported))) {
696 gss_supported = NULL;
697 return 0;
698 }
626 699
627 /* Check to see if the mechanism is usable before we offer it */ 700 /* Check to see if the mechanism is usable before we offer it */
628 while (mech < gss_supported->count && !ok) { 701 while (mech < gss_supported->count && !ok) {
629 /* My DER encoding requires length<128 */ 702 /* My DER encoding requires length<128 */
630 if (gss_supported->elements[mech].length < 128 && 703 if (gss_supported->elements[mech].length < 128 &&
631 ssh_gssapi_check_mechanism(&gssctxt, 704 ssh_gssapi_check_mechanism(&gssctxt,
632 &gss_supported->elements[mech], authctxt->host)) { 705 &gss_supported->elements[mech], gss_host,
706 options.gss_client_identity)) {
633 ok = 1; /* Mechanism works */ 707 ok = 1; /* Mechanism works */
634 } else { 708 } else {
635 mech++; 709 mech++;
@@ -726,8 +800,8 @@ input_gssapi_response(int type, u_int32_t plen, void *ctxt)
726{ 800{
727 Authctxt *authctxt = ctxt; 801 Authctxt *authctxt = ctxt;
728 Gssctxt *gssctxt; 802 Gssctxt *gssctxt;
729 int oidlen; 803 u_int oidlen;
730 char *oidv; 804 u_char *oidv;
731 805
732 if (authctxt == NULL) 806 if (authctxt == NULL)
733 fatal("input_gssapi_response: no authentication context"); 807 fatal("input_gssapi_response: no authentication context");
@@ -836,6 +910,48 @@ input_gssapi_error(int type, u_int32_t plen, void *ctxt)
836 free(msg); 910 free(msg);
837 free(lang); 911 free(lang);
838} 912}
913
914int
915userauth_gsskeyex(Authctxt *authctxt)
916{
917 Buffer b;
918 gss_buffer_desc gssbuf;
919 gss_buffer_desc mic = GSS_C_EMPTY_BUFFER;
920 OM_uint32 ms;
921
922 static int attempt = 0;
923 if (attempt++ >= 1)
924 return (0);
925
926 if (gss_kex_context == NULL) {
927 debug("No valid Key exchange context");
928 return (0);
929 }
930
931 ssh_gssapi_buildmic(&b, authctxt->server_user, authctxt->service,
932 "gssapi-keyex");
933
934 gssbuf.value = buffer_ptr(&b);
935 gssbuf.length = buffer_len(&b);
936
937 if (GSS_ERROR(ssh_gssapi_sign(gss_kex_context, &gssbuf, &mic))) {
938 buffer_free(&b);
939 return (0);
940 }
941
942 packet_start(SSH2_MSG_USERAUTH_REQUEST);
943 packet_put_cstring(authctxt->server_user);
944 packet_put_cstring(authctxt->service);
945 packet_put_cstring(authctxt->method->name);
946 packet_put_string(mic.value, mic.length);
947 packet_send();
948
949 buffer_free(&b);
950 gss_release_buffer(&ms, &mic);
951
952 return (1);
953}
954
839#endif /* GSSAPI */ 955#endif /* GSSAPI */
840 956
841int 957int