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-08-19 17:09:55 +0100
commit5d3dc7ea4c96cab9483d5389a3b04163771fdee2 (patch)
treed20c6ac4435c138f3eefbc73caa649bcdfbcfb80 /sshconnect2.c
parent544df7a04ae5b5c1fc30be7c445ad685d7a02dc9 (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-08-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 fcaed6b01..44c89e691 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 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;
@@ -200,6 +225,17 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port)
200 myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal( 225 myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal(
201 myproposal[PROPOSAL_KEX_ALGS]); 226 myproposal[PROPOSAL_KEX_ALGS]);
202 227
228#ifdef GSSAPI
229 /* If we've got GSSAPI algorithms, then we also support the
230 * 'null' hostkey, as a last resort */
231 if (options.gss_keyex && gss) {
232 orig = myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS];
233 xasprintf(&myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS],
234 "%s,null", orig);
235 free(gss);
236 }
237#endif
238
203 if (options.rekey_limit || options.rekey_interval) 239 if (options.rekey_limit || options.rekey_interval)
204 packet_set_rekey_limits((u_int32_t)options.rekey_limit, 240 packet_set_rekey_limits((u_int32_t)options.rekey_limit,
205 (time_t)options.rekey_interval); 241 (time_t)options.rekey_interval);
@@ -218,10 +254,30 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port)
218# endif 254# endif
219#endif 255#endif
220 kex->kex[KEX_C25519_SHA256] = kexc25519_client; 256 kex->kex[KEX_C25519_SHA256] = kexc25519_client;
257#ifdef GSSAPI
258 if (options.gss_keyex) {
259 kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_client;
260 kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_client;
261 kex->kex[KEX_GSS_GEX_SHA1] = kexgss_client;
262 }
263#endif
221 kex->client_version_string=client_version_string; 264 kex->client_version_string=client_version_string;
222 kex->server_version_string=server_version_string; 265 kex->server_version_string=server_version_string;
223 kex->verify_host_key=&verify_host_key_callback; 266 kex->verify_host_key=&verify_host_key_callback;
224 267
268#ifdef GSSAPI
269 if (options.gss_keyex) {
270 kex->gss_deleg_creds = options.gss_deleg_creds;
271 kex->gss_trust_dns = options.gss_trust_dns;
272 kex->gss_client = options.gss_client_identity;
273 if (options.gss_server_identity) {
274 kex->gss_host = options.gss_server_identity;
275 } else {
276 kex->gss_host = gss_host;
277 }
278 }
279#endif
280
225 dispatch_run(DISPATCH_BLOCK, &kex->done, active_state); 281 dispatch_run(DISPATCH_BLOCK, &kex->done, active_state);
226 282
227 if (options.use_roaming && !kex->roaming) { 283 if (options.use_roaming && !kex->roaming) {
@@ -313,6 +369,7 @@ int input_gssapi_token(int type, u_int32_t, void *);
313int input_gssapi_hash(int type, u_int32_t, void *); 369int input_gssapi_hash(int type, u_int32_t, void *);
314int input_gssapi_error(int, u_int32_t, void *); 370int input_gssapi_error(int, u_int32_t, void *);
315int input_gssapi_errtok(int, u_int32_t, void *); 371int input_gssapi_errtok(int, u_int32_t, void *);
372int userauth_gsskeyex(Authctxt *authctxt);
316#endif 373#endif
317 374
318void userauth(Authctxt *, char *); 375void userauth(Authctxt *, char *);
@@ -328,6 +385,11 @@ static char *authmethods_get(void);
328 385
329Authmethod authmethods[] = { 386Authmethod authmethods[] = {
330#ifdef GSSAPI 387#ifdef GSSAPI
388 {"gssapi-keyex",
389 userauth_gsskeyex,
390 NULL,
391 &options.gss_authentication,
392 NULL},
331 {"gssapi-with-mic", 393 {"gssapi-with-mic",
332 userauth_gssapi, 394 userauth_gssapi,
333 NULL, 395 NULL,
@@ -634,19 +696,31 @@ userauth_gssapi(Authctxt *authctxt)
634 static u_int mech = 0; 696 static u_int mech = 0;
635 OM_uint32 min; 697 OM_uint32 min;
636 int ok = 0; 698 int ok = 0;
699 const char *gss_host;
700
701 if (options.gss_server_identity)
702 gss_host = options.gss_server_identity;
703 else if (options.gss_trust_dns)
704 gss_host = get_canonical_hostname(1);
705 else
706 gss_host = authctxt->host;
637 707
638 /* Try one GSSAPI method at a time, rather than sending them all at 708 /* Try one GSSAPI method at a time, rather than sending them all at
639 * once. */ 709 * once. */
640 710
641 if (gss_supported == NULL) 711 if (gss_supported == NULL)
642 gss_indicate_mechs(&min, &gss_supported); 712 if (GSS_ERROR(gss_indicate_mechs(&min, &gss_supported))) {
713 gss_supported = NULL;
714 return 0;
715 }
643 716
644 /* Check to see if the mechanism is usable before we offer it */ 717 /* Check to see if the mechanism is usable before we offer it */
645 while (mech < gss_supported->count && !ok) { 718 while (mech < gss_supported->count && !ok) {
646 /* My DER encoding requires length<128 */ 719 /* My DER encoding requires length<128 */
647 if (gss_supported->elements[mech].length < 128 && 720 if (gss_supported->elements[mech].length < 128 &&
648 ssh_gssapi_check_mechanism(&gssctxt, 721 ssh_gssapi_check_mechanism(&gssctxt,
649 &gss_supported->elements[mech], authctxt->host)) { 722 &gss_supported->elements[mech], gss_host,
723 options.gss_client_identity)) {
650 ok = 1; /* Mechanism works */ 724 ok = 1; /* Mechanism works */
651 } else { 725 } else {
652 mech++; 726 mech++;
@@ -743,8 +817,8 @@ input_gssapi_response(int type, u_int32_t plen, void *ctxt)
743{ 817{
744 Authctxt *authctxt = ctxt; 818 Authctxt *authctxt = ctxt;
745 Gssctxt *gssctxt; 819 Gssctxt *gssctxt;
746 int oidlen; 820 u_int oidlen;
747 char *oidv; 821 u_char *oidv;
748 822
749 if (authctxt == NULL) 823 if (authctxt == NULL)
750 fatal("input_gssapi_response: no authentication context"); 824 fatal("input_gssapi_response: no authentication context");
@@ -857,6 +931,48 @@ input_gssapi_error(int type, u_int32_t plen, void *ctxt)
857 free(lang); 931 free(lang);
858 return 0; 932 return 0;
859} 933}
934
935int
936userauth_gsskeyex(Authctxt *authctxt)
937{
938 Buffer b;
939 gss_buffer_desc gssbuf;
940 gss_buffer_desc mic = GSS_C_EMPTY_BUFFER;
941 OM_uint32 ms;
942
943 static int attempt = 0;
944 if (attempt++ >= 1)
945 return (0);
946
947 if (gss_kex_context == NULL) {
948 debug("No valid Key exchange context");
949 return (0);
950 }
951
952 ssh_gssapi_buildmic(&b, authctxt->server_user, authctxt->service,
953 "gssapi-keyex");
954
955 gssbuf.value = buffer_ptr(&b);
956 gssbuf.length = buffer_len(&b);
957
958 if (GSS_ERROR(ssh_gssapi_sign(gss_kex_context, &gssbuf, &mic))) {
959 buffer_free(&b);
960 return (0);
961 }
962
963 packet_start(SSH2_MSG_USERAUTH_REQUEST);
964 packet_put_cstring(authctxt->server_user);
965 packet_put_cstring(authctxt->service);
966 packet_put_cstring(authctxt->method->name);
967 packet_put_string(mic.value, mic.length);
968 packet_send();
969
970 buffer_free(&b);
971 gss_release_buffer(&ms, &mic);
972
973 return (1);
974}
975
860#endif /* GSSAPI */ 976#endif /* GSSAPI */
861 977
862int 978int