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-10 02:40:08 +0000
commitcd404114ded78fc51d5d9cbd458d55c9b2f67daa (patch)
treedf7a424d9301b69af906b50d550bfce6e6e2c5f3 /sshconnect2.c
parent9a975a9faed7c4f334e8c8490db3e77e102f2b21 (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-02-10 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 8acffc5c3..21a269d3c 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;
@@ -198,6 +223,17 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port)
198 if (options.kex_algorithms != NULL) 223 if (options.kex_algorithms != NULL)
199 myproposal[PROPOSAL_KEX_ALGS] = options.kex_algorithms; 224 myproposal[PROPOSAL_KEX_ALGS] = options.kex_algorithms;
200 225
226#ifdef GSSAPI
227 /* If we've got GSSAPI algorithms, then we also support the
228 * 'null' hostkey, as a last resort */
229 if (options.gss_keyex && gss) {
230 orig = myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS];
231 xasprintf(&myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS],
232 "%s,null", orig);
233 free(gss);
234 }
235#endif
236
201 if (options.rekey_limit || options.rekey_interval) 237 if (options.rekey_limit || options.rekey_interval)
202 packet_set_rekey_limits((u_int32_t)options.rekey_limit, 238 packet_set_rekey_limits((u_int32_t)options.rekey_limit,
203 (time_t)options.rekey_interval); 239 (time_t)options.rekey_interval);
@@ -210,10 +246,30 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port)
210 kex->kex[KEX_DH_GEX_SHA256] = kexgex_client; 246 kex->kex[KEX_DH_GEX_SHA256] = kexgex_client;
211 kex->kex[KEX_ECDH_SHA2] = kexecdh_client; 247 kex->kex[KEX_ECDH_SHA2] = kexecdh_client;
212 kex->kex[KEX_C25519_SHA256] = kexc25519_client; 248 kex->kex[KEX_C25519_SHA256] = kexc25519_client;
249#ifdef GSSAPI
250 if (options.gss_keyex) {
251 kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_client;
252 kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_client;
253 kex->kex[KEX_GSS_GEX_SHA1] = kexgss_client;
254 }
255#endif
213 kex->client_version_string=client_version_string; 256 kex->client_version_string=client_version_string;
214 kex->server_version_string=server_version_string; 257 kex->server_version_string=server_version_string;
215 kex->verify_host_key=&verify_host_key_callback; 258 kex->verify_host_key=&verify_host_key_callback;
216 259
260#ifdef GSSAPI
261 if (options.gss_keyex) {
262 kex->gss_deleg_creds = options.gss_deleg_creds;
263 kex->gss_trust_dns = options.gss_trust_dns;
264 kex->gss_client = options.gss_client_identity;
265 if (options.gss_server_identity) {
266 kex->gss_host = options.gss_server_identity;
267 } else {
268 kex->gss_host = gss_host;
269 }
270 }
271#endif
272
217 xxx_kex = kex; 273 xxx_kex = kex;
218 274
219 dispatch_run(DISPATCH_BLOCK, &kex->done, kex); 275 dispatch_run(DISPATCH_BLOCK, &kex->done, kex);
@@ -309,6 +365,7 @@ void input_gssapi_token(int type, u_int32_t, void *);
309void input_gssapi_hash(int type, u_int32_t, void *); 365void input_gssapi_hash(int type, u_int32_t, void *);
310void input_gssapi_error(int, u_int32_t, void *); 366void input_gssapi_error(int, u_int32_t, void *);
311void input_gssapi_errtok(int, u_int32_t, void *); 367void input_gssapi_errtok(int, u_int32_t, void *);
368int userauth_gsskeyex(Authctxt *authctxt);
312#endif 369#endif
313 370
314void userauth(Authctxt *, char *); 371void userauth(Authctxt *, char *);
@@ -324,6 +381,11 @@ static char *authmethods_get(void);
324 381
325Authmethod authmethods[] = { 382Authmethod authmethods[] = {
326#ifdef GSSAPI 383#ifdef GSSAPI
384 {"gssapi-keyex",
385 userauth_gsskeyex,
386 NULL,
387 &options.gss_authentication,
388 NULL},
327 {"gssapi-with-mic", 389 {"gssapi-with-mic",
328 userauth_gssapi, 390 userauth_gssapi,
329 NULL, 391 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");
@@ -846,6 +920,48 @@ input_gssapi_error(int type, u_int32_t plen, void *ctxt)
846 free(msg); 920 free(msg);
847 free(lang); 921 free(lang);
848} 922}
923
924int
925userauth_gsskeyex(Authctxt *authctxt)
926{
927 Buffer b;
928 gss_buffer_desc gssbuf;
929 gss_buffer_desc mic = GSS_C_EMPTY_BUFFER;
930 OM_uint32 ms;
931
932 static int attempt = 0;
933 if (attempt++ >= 1)
934 return (0);
935
936 if (gss_kex_context == NULL) {
937 debug("No valid Key exchange context");
938 return (0);
939 }
940
941 ssh_gssapi_buildmic(&b, authctxt->server_user, authctxt->service,
942 "gssapi-keyex");
943
944 gssbuf.value = buffer_ptr(&b);
945 gssbuf.length = buffer_len(&b);
946
947 if (GSS_ERROR(ssh_gssapi_sign(gss_kex_context, &gssbuf, &mic))) {
948 buffer_free(&b);
949 return (0);
950 }
951
952 packet_start(SSH2_MSG_USERAUTH_REQUEST);
953 packet_put_cstring(authctxt->server_user);
954 packet_put_cstring(authctxt->service);
955 packet_put_cstring(authctxt->method->name);
956 packet_put_string(mic.value, mic.length);
957 packet_send();
958
959 buffer_free(&b);
960 gss_release_buffer(&ms, &mic);
961
962 return (1);
963}
964
849#endif /* GSSAPI */ 965#endif /* GSSAPI */
850 966
851int 967int