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-03-20 00:24:48 +0000
commit9dfcd1a0e691c1cad34b168e27b3ed31ab6986cd (patch)
tree3a19744ef1cf261141a522e13f75abbb3b7dba4b /sshconnect2.c
parent796ba4fd011b5d0d9d78d592ba2f30fc9d5ed2e7 (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-03-19 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 7f4ff4189..66cb03527 100644
--- a/sshconnect2.c
+++ b/sshconnect2.c
@@ -158,9 +158,34 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port)
158{ 158{
159 Kex *kex; 159 Kex *kex;
160 160
161#ifdef GSSAPI
162 char *orig = NULL, *gss = NULL;
163 char *gss_host = NULL;
164#endif
165
161 xxx_host = host; 166 xxx_host = host;
162 xxx_hostaddr = hostaddr; 167 xxx_hostaddr = hostaddr;
163 168
169#ifdef GSSAPI
170 if (options.gss_keyex) {
171 /* Add the GSSAPI mechanisms currently supported on this
172 * client to the key exchange algorithm proposal */
173 orig = myproposal[PROPOSAL_KEX_ALGS];
174
175 if (options.gss_trust_dns)
176 gss_host = (char *)get_canonical_hostname(1);
177 else
178 gss_host = host;
179
180 gss = ssh_gssapi_client_mechanisms(gss_host, options.gss_client_identity);
181 if (gss) {
182 debug("Offering GSSAPI proposal: %s", gss);
183 xasprintf(&myproposal[PROPOSAL_KEX_ALGS],
184 "%s,%s", gss, orig);
185 }
186 }
187#endif
188
164 if (options.ciphers == (char *)-1) { 189 if (options.ciphers == (char *)-1) {
165 logit("No valid ciphers for protocol version 2 given, using defaults."); 190 logit("No valid ciphers for protocol version 2 given, using defaults.");
166 options.ciphers = NULL; 191 options.ciphers = NULL;
@@ -196,6 +221,17 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port)
196 if (options.kex_algorithms != NULL) 221 if (options.kex_algorithms != NULL)
197 myproposal[PROPOSAL_KEX_ALGS] = options.kex_algorithms; 222 myproposal[PROPOSAL_KEX_ALGS] = options.kex_algorithms;
198 223
224#ifdef GSSAPI
225 /* If we've got GSSAPI algorithms, then we also support the
226 * 'null' hostkey, as a last resort */
227 if (options.gss_keyex && gss) {
228 orig = myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS];
229 xasprintf(&myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS],
230 "%s,null", orig);
231 free(gss);
232 }
233#endif
234
199 if (options.rekey_limit || options.rekey_interval) 235 if (options.rekey_limit || options.rekey_interval)
200 packet_set_rekey_limits((u_int32_t)options.rekey_limit, 236 packet_set_rekey_limits((u_int32_t)options.rekey_limit,
201 (time_t)options.rekey_interval); 237 (time_t)options.rekey_interval);
@@ -208,10 +244,30 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port)
208 kex->kex[KEX_DH_GEX_SHA256] = kexgex_client; 244 kex->kex[KEX_DH_GEX_SHA256] = kexgex_client;
209 kex->kex[KEX_ECDH_SHA2] = kexecdh_client; 245 kex->kex[KEX_ECDH_SHA2] = kexecdh_client;
210 kex->kex[KEX_C25519_SHA256] = kexc25519_client; 246 kex->kex[KEX_C25519_SHA256] = kexc25519_client;
247#ifdef GSSAPI
248 if (options.gss_keyex) {
249 kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_client;
250 kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_client;
251 kex->kex[KEX_GSS_GEX_SHA1] = kexgss_client;
252 }
253#endif
211 kex->client_version_string=client_version_string; 254 kex->client_version_string=client_version_string;
212 kex->server_version_string=server_version_string; 255 kex->server_version_string=server_version_string;
213 kex->verify_host_key=&verify_host_key_callback; 256 kex->verify_host_key=&verify_host_key_callback;
214 257
258#ifdef GSSAPI
259 if (options.gss_keyex) {
260 kex->gss_deleg_creds = options.gss_deleg_creds;
261 kex->gss_trust_dns = options.gss_trust_dns;
262 kex->gss_client = options.gss_client_identity;
263 if (options.gss_server_identity) {
264 kex->gss_host = options.gss_server_identity;
265 } else {
266 kex->gss_host = gss_host;
267 }
268 }
269#endif
270
215 xxx_kex = kex; 271 xxx_kex = kex;
216 272
217 dispatch_run(DISPATCH_BLOCK, &kex->done, kex); 273 dispatch_run(DISPATCH_BLOCK, &kex->done, kex);
@@ -301,6 +357,7 @@ void input_gssapi_token(int type, u_int32_t, void *);
301void input_gssapi_hash(int type, u_int32_t, void *); 357void input_gssapi_hash(int type, u_int32_t, void *);
302void input_gssapi_error(int, u_int32_t, void *); 358void input_gssapi_error(int, u_int32_t, void *);
303void input_gssapi_errtok(int, u_int32_t, void *); 359void input_gssapi_errtok(int, u_int32_t, void *);
360int userauth_gsskeyex(Authctxt *authctxt);
304#endif 361#endif
305 362
306void userauth(Authctxt *, char *); 363void userauth(Authctxt *, char *);
@@ -316,6 +373,11 @@ static char *authmethods_get(void);
316 373
317Authmethod authmethods[] = { 374Authmethod authmethods[] = {
318#ifdef GSSAPI 375#ifdef GSSAPI
376 {"gssapi-keyex",
377 userauth_gsskeyex,
378 NULL,
379 &options.gss_authentication,
380 NULL},
319 {"gssapi-with-mic", 381 {"gssapi-with-mic",
320 userauth_gssapi, 382 userauth_gssapi,
321 NULL, 383 NULL,
@@ -612,19 +674,31 @@ userauth_gssapi(Authctxt *authctxt)
612 static u_int mech = 0; 674 static u_int mech = 0;
613 OM_uint32 min; 675 OM_uint32 min;
614 int ok = 0; 676 int ok = 0;
677 const char *gss_host;
678
679 if (options.gss_server_identity)
680 gss_host = options.gss_server_identity;
681 else if (options.gss_trust_dns)
682 gss_host = get_canonical_hostname(1);
683 else
684 gss_host = authctxt->host;
615 685
616 /* Try one GSSAPI method at a time, rather than sending them all at 686 /* Try one GSSAPI method at a time, rather than sending them all at
617 * once. */ 687 * once. */
618 688
619 if (gss_supported == NULL) 689 if (gss_supported == NULL)
620 gss_indicate_mechs(&min, &gss_supported); 690 if (GSS_ERROR(gss_indicate_mechs(&min, &gss_supported))) {
691 gss_supported = NULL;
692 return 0;
693 }
621 694
622 /* Check to see if the mechanism is usable before we offer it */ 695 /* Check to see if the mechanism is usable before we offer it */
623 while (mech < gss_supported->count && !ok) { 696 while (mech < gss_supported->count && !ok) {
624 /* My DER encoding requires length<128 */ 697 /* My DER encoding requires length<128 */
625 if (gss_supported->elements[mech].length < 128 && 698 if (gss_supported->elements[mech].length < 128 &&
626 ssh_gssapi_check_mechanism(&gssctxt, 699 ssh_gssapi_check_mechanism(&gssctxt,
627 &gss_supported->elements[mech], authctxt->host)) { 700 &gss_supported->elements[mech], gss_host,
701 options.gss_client_identity)) {
628 ok = 1; /* Mechanism works */ 702 ok = 1; /* Mechanism works */
629 } else { 703 } else {
630 mech++; 704 mech++;
@@ -721,8 +795,8 @@ input_gssapi_response(int type, u_int32_t plen, void *ctxt)
721{ 795{
722 Authctxt *authctxt = ctxt; 796 Authctxt *authctxt = ctxt;
723 Gssctxt *gssctxt; 797 Gssctxt *gssctxt;
724 int oidlen; 798 u_int oidlen;
725 char *oidv; 799 u_char *oidv;
726 800
727 if (authctxt == NULL) 801 if (authctxt == NULL)
728 fatal("input_gssapi_response: no authentication context"); 802 fatal("input_gssapi_response: no authentication context");
@@ -831,6 +905,48 @@ input_gssapi_error(int type, u_int32_t plen, void *ctxt)
831 free(msg); 905 free(msg);
832 free(lang); 906 free(lang);
833} 907}
908
909int
910userauth_gsskeyex(Authctxt *authctxt)
911{
912 Buffer b;
913 gss_buffer_desc gssbuf;
914 gss_buffer_desc mic = GSS_C_EMPTY_BUFFER;
915 OM_uint32 ms;
916
917 static int attempt = 0;
918 if (attempt++ >= 1)
919 return (0);
920
921 if (gss_kex_context == NULL) {
922 debug("No valid Key exchange context");
923 return (0);
924 }
925
926 ssh_gssapi_buildmic(&b, authctxt->server_user, authctxt->service,
927 "gssapi-keyex");
928
929 gssbuf.value = buffer_ptr(&b);
930 gssbuf.length = buffer_len(&b);
931
932 if (GSS_ERROR(ssh_gssapi_sign(gss_kex_context, &gssbuf, &mic))) {
933 buffer_free(&b);
934 return (0);
935 }
936
937 packet_start(SSH2_MSG_USERAUTH_REQUEST);
938 packet_put_cstring(authctxt->server_user);
939 packet_put_cstring(authctxt->service);
940 packet_put_cstring(authctxt->method->name);
941 packet_put_string(mic.value, mic.length);
942 packet_send();
943
944 buffer_free(&b);
945 gss_release_buffer(&ms, &mic);
946
947 return (1);
948}
949
834#endif /* GSSAPI */ 950#endif /* GSSAPI */
835 951
836int 952int