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-02-09 16:16:58 +0000
commit950be7e1b1a01ee9b25e2a72726a6370b8acacb6 (patch)
tree64829a84f903d7e2d3270c43e3f80df7db2a6a10 /sshconnect2.c
parentee196dab7c5f97f0b80c8099343a375bead92010 (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: 2013-11-09 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 70e3cd8c9..0b13530ce 100644
--- a/sshconnect2.c
+++ b/sshconnect2.c
@@ -160,9 +160,34 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port)
160{ 160{
161 Kex *kex; 161 Kex *kex;
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 if (options.ciphers == (char *)-1) { 191 if (options.ciphers == (char *)-1) {
167 logit("No valid ciphers for protocol version 2 given, using defaults."); 192 logit("No valid ciphers for protocol version 2 given, using defaults.");
168 options.ciphers = NULL; 193 options.ciphers = NULL;
@@ -197,6 +222,17 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port)
197 if (options.kex_algorithms != NULL) 222 if (options.kex_algorithms != NULL)
198 myproposal[PROPOSAL_KEX_ALGS] = options.kex_algorithms; 223 myproposal[PROPOSAL_KEX_ALGS] = options.kex_algorithms;
199 224
225#ifdef GSSAPI
226 /* If we've got GSSAPI algorithms, then we also support the
227 * 'null' hostkey, as a last resort */
228 if (options.gss_keyex && gss) {
229 orig = myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS];
230 xasprintf(&myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS],
231 "%s,null", orig);
232 free(gss);
233 }
234#endif
235
200 if (options.rekey_limit || options.rekey_interval) 236 if (options.rekey_limit || options.rekey_interval)
201 packet_set_rekey_limits((u_int32_t)options.rekey_limit, 237 packet_set_rekey_limits((u_int32_t)options.rekey_limit,
202 (time_t)options.rekey_interval); 238 (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_SHA1] = kexgex_client; 244 kex->kex[KEX_DH_GEX_SHA1] = kexgex_client;
209 kex->kex[KEX_DH_GEX_SHA256] = kexgex_client; 245 kex->kex[KEX_DH_GEX_SHA256] = kexgex_client;
210 kex->kex[KEX_ECDH_SHA2] = kexecdh_client; 246 kex->kex[KEX_ECDH_SHA2] = kexecdh_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);
@@ -307,6 +363,7 @@ void input_gssapi_token(int type, u_int32_t, void *);
307void input_gssapi_hash(int type, u_int32_t, void *); 363void input_gssapi_hash(int type, u_int32_t, void *);
308void input_gssapi_error(int, u_int32_t, void *); 364void input_gssapi_error(int, u_int32_t, void *);
309void input_gssapi_errtok(int, u_int32_t, void *); 365void input_gssapi_errtok(int, u_int32_t, void *);
366int userauth_gsskeyex(Authctxt *authctxt);
310#endif 367#endif
311 368
312void userauth(Authctxt *, char *); 369void userauth(Authctxt *, char *);
@@ -322,6 +379,11 @@ static char *authmethods_get(void);
322 379
323Authmethod authmethods[] = { 380Authmethod authmethods[] = {
324#ifdef GSSAPI 381#ifdef GSSAPI
382 {"gssapi-keyex",
383 userauth_gsskeyex,
384 NULL,
385 &options.gss_authentication,
386 NULL},
325 {"gssapi-with-mic", 387 {"gssapi-with-mic",
326 userauth_gssapi, 388 userauth_gssapi,
327 NULL, 389 NULL,
@@ -625,19 +687,31 @@ userauth_gssapi(Authctxt *authctxt)
625 static u_int mech = 0; 687 static u_int mech = 0;
626 OM_uint32 min; 688 OM_uint32 min;
627 int ok = 0; 689 int ok = 0;
690 const char *gss_host;
691
692 if (options.gss_server_identity)
693 gss_host = options.gss_server_identity;
694 else if (options.gss_trust_dns)
695 gss_host = get_canonical_hostname(1);
696 else
697 gss_host = authctxt->host;
628 698
629 /* Try one GSSAPI method at a time, rather than sending them all at 699 /* Try one GSSAPI method at a time, rather than sending them all at
630 * once. */ 700 * once. */
631 701
632 if (gss_supported == NULL) 702 if (gss_supported == NULL)
633 gss_indicate_mechs(&min, &gss_supported); 703 if (GSS_ERROR(gss_indicate_mechs(&min, &gss_supported))) {
704 gss_supported = NULL;
705 return 0;
706 }
634 707
635 /* Check to see if the mechanism is usable before we offer it */ 708 /* Check to see if the mechanism is usable before we offer it */
636 while (mech < gss_supported->count && !ok) { 709 while (mech < gss_supported->count && !ok) {
637 /* My DER encoding requires length<128 */ 710 /* My DER encoding requires length<128 */
638 if (gss_supported->elements[mech].length < 128 && 711 if (gss_supported->elements[mech].length < 128 &&
639 ssh_gssapi_check_mechanism(&gssctxt, 712 ssh_gssapi_check_mechanism(&gssctxt,
640 &gss_supported->elements[mech], authctxt->host)) { 713 &gss_supported->elements[mech], gss_host,
714 options.gss_client_identity)) {
641 ok = 1; /* Mechanism works */ 715 ok = 1; /* Mechanism works */
642 } else { 716 } else {
643 mech++; 717 mech++;
@@ -734,8 +808,8 @@ input_gssapi_response(int type, u_int32_t plen, void *ctxt)
734{ 808{
735 Authctxt *authctxt = ctxt; 809 Authctxt *authctxt = ctxt;
736 Gssctxt *gssctxt; 810 Gssctxt *gssctxt;
737 int oidlen; 811 u_int oidlen;
738 char *oidv; 812 u_char *oidv;
739 813
740 if (authctxt == NULL) 814 if (authctxt == NULL)
741 fatal("input_gssapi_response: no authentication context"); 815 fatal("input_gssapi_response: no authentication context");
@@ -844,6 +918,48 @@ input_gssapi_error(int type, u_int32_t plen, void *ctxt)
844 free(msg); 918 free(msg);
845 free(lang); 919 free(lang);
846} 920}
921
922int
923userauth_gsskeyex(Authctxt *authctxt)
924{
925 Buffer b;
926 gss_buffer_desc gssbuf;
927 gss_buffer_desc mic = GSS_C_EMPTY_BUFFER;
928 OM_uint32 ms;
929
930 static int attempt = 0;
931 if (attempt++ >= 1)
932 return (0);
933
934 if (gss_kex_context == NULL) {
935 debug("No valid Key exchange context");
936 return (0);
937 }
938
939 ssh_gssapi_buildmic(&b, authctxt->server_user, authctxt->service,
940 "gssapi-keyex");
941
942 gssbuf.value = buffer_ptr(&b);
943 gssbuf.length = buffer_len(&b);
944
945 if (GSS_ERROR(ssh_gssapi_sign(gss_kex_context, &gssbuf, &mic))) {
946 buffer_free(&b);
947 return (0);
948 }
949
950 packet_start(SSH2_MSG_USERAUTH_REQUEST);
951 packet_put_cstring(authctxt->server_user);
952 packet_put_cstring(authctxt->service);
953 packet_put_cstring(authctxt->method->name);
954 packet_put_string(mic.value, mic.length);
955 packet_send();
956
957 buffer_free(&b);
958 gss_release_buffer(&ms, &mic);
959
960 return (1);
961}
962
847#endif /* GSSAPI */ 963#endif /* GSSAPI */
848 964
849int 965int