summaryrefslogtreecommitdiff
path: root/sshconnect2.c
diff options
context:
space:
mode:
Diffstat (limited to 'sshconnect2.c')
-rw-r--r--sshconnect2.c154
1 files changed, 149 insertions, 5 deletions
diff --git a/sshconnect2.c b/sshconnect2.c
index 1a6545edf..79a22e600 100644
--- a/sshconnect2.c
+++ b/sshconnect2.c
@@ -80,8 +80,6 @@
80#endif 80#endif
81 81
82/* import */ 82/* import */
83extern char *client_version_string;
84extern char *server_version_string;
85extern Options options; 83extern Options options;
86 84
87/* 85/*
@@ -163,6 +161,11 @@ ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port)
163 char *s, *all_key; 161 char *s, *all_key;
164 int r, use_known_hosts_order = 0; 162 int r, use_known_hosts_order = 0;
165 163
164#if defined(GSSAPI) && defined(WITH_OPENSSL)
165 char *orig = NULL, *gss = NULL;
166 char *gss_host = NULL;
167#endif
168
166 xxx_host = host; 169 xxx_host = host;
167 xxx_hostaddr = hostaddr; 170 xxx_hostaddr = hostaddr;
168 171
@@ -206,6 +209,41 @@ ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port)
206 compat_pkalg_proposal(options.hostkeyalgorithms); 209 compat_pkalg_proposal(options.hostkeyalgorithms);
207 } 210 }
208 211
212#if defined(GSSAPI) && defined(WITH_OPENSSL)
213 if (options.gss_keyex) {
214 /* Add the GSSAPI mechanisms currently supported on this
215 * client to the key exchange algorithm proposal */
216 orig = myproposal[PROPOSAL_KEX_ALGS];
217
218 if (options.gss_server_identity) {
219 gss_host = xstrdup(options.gss_server_identity);
220 } else if (options.gss_trust_dns) {
221 gss_host = remote_hostname(ssh);
222 /* Fall back to specified host if we are using proxy command
223 * and can not use DNS on that socket */
224 if (strcmp(gss_host, "UNKNOWN") == 0) {
225 gss_host = xstrdup(host);
226 }
227 } else {
228 gss_host = xstrdup(host);
229 }
230
231 gss = ssh_gssapi_client_mechanisms(gss_host,
232 options.gss_client_identity, options.gss_kex_algorithms);
233 if (gss) {
234 debug("Offering GSSAPI proposal: %s", gss);
235 xasprintf(&myproposal[PROPOSAL_KEX_ALGS],
236 "%s,%s", gss, orig);
237
238 /* If we've got GSSAPI algorithms, then we also support the
239 * 'null' hostkey, as a last resort */
240 orig = myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS];
241 xasprintf(&myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS],
242 "%s,null", orig);
243 }
244 }
245#endif
246
209 if (options.rekey_limit || options.rekey_interval) 247 if (options.rekey_limit || options.rekey_interval)
210 ssh_packet_set_rekey_limits(ssh, options.rekey_limit, 248 ssh_packet_set_rekey_limits(ssh, options.rekey_limit,
211 options.rekey_interval); 249 options.rekey_interval);
@@ -224,16 +262,46 @@ ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port)
224# ifdef OPENSSL_HAS_ECC 262# ifdef OPENSSL_HAS_ECC
225 ssh->kex->kex[KEX_ECDH_SHA2] = kex_gen_client; 263 ssh->kex->kex[KEX_ECDH_SHA2] = kex_gen_client;
226# endif 264# endif
227#endif 265# ifdef GSSAPI
266 if (options.gss_keyex) {
267 ssh->kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_client;
268 ssh->kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_client;
269 ssh->kex->kex[KEX_GSS_GRP14_SHA256] = kexgss_client;
270 ssh->kex->kex[KEX_GSS_GRP16_SHA512] = kexgss_client;
271 ssh->kex->kex[KEX_GSS_GEX_SHA1] = kexgssgex_client;
272 ssh->kex->kex[KEX_GSS_NISTP256_SHA256] = kexgss_client;
273 ssh->kex->kex[KEX_GSS_C25519_SHA256] = kexgss_client;
274 }
275# endif
276#endif /* WITH_OPENSSL */
228 ssh->kex->kex[KEX_C25519_SHA256] = kex_gen_client; 277 ssh->kex->kex[KEX_C25519_SHA256] = kex_gen_client;
229 ssh->kex->kex[KEX_KEM_SNTRUP4591761X25519_SHA512] = kex_gen_client; 278 ssh->kex->kex[KEX_KEM_SNTRUP4591761X25519_SHA512] = kex_gen_client;
230 ssh->kex->verify_host_key=&verify_host_key_callback; 279 ssh->kex->verify_host_key=&verify_host_key_callback;
231 280
281#if defined(GSSAPI) && defined(WITH_OPENSSL)
282 if (options.gss_keyex) {
283 ssh->kex->gss_deleg_creds = options.gss_deleg_creds;
284 ssh->kex->gss_trust_dns = options.gss_trust_dns;
285 ssh->kex->gss_client = options.gss_client_identity;
286 ssh->kex->gss_host = gss_host;
287 }
288#endif
289
232 ssh_dispatch_run_fatal(ssh, DISPATCH_BLOCK, &ssh->kex->done); 290 ssh_dispatch_run_fatal(ssh, DISPATCH_BLOCK, &ssh->kex->done);
233 291
234 /* remove ext-info from the KEX proposals for rekeying */ 292 /* remove ext-info from the KEX proposals for rekeying */
235 myproposal[PROPOSAL_KEX_ALGS] = 293 myproposal[PROPOSAL_KEX_ALGS] =
236 compat_kex_proposal(options.kex_algorithms); 294 compat_kex_proposal(options.kex_algorithms);
295#if defined(GSSAPI) && defined(WITH_OPENSSL)
296 /* repair myproposal after it was crumpled by the */
297 /* ext-info removal above */
298 if (gss) {
299 orig = myproposal[PROPOSAL_KEX_ALGS];
300 xasprintf(&myproposal[PROPOSAL_KEX_ALGS],
301 "%s,%s", gss, orig);
302 free(gss);
303 }
304#endif
237 if ((r = kex_prop2buf(ssh->kex->my, myproposal)) != 0) 305 if ((r = kex_prop2buf(ssh->kex->my, myproposal)) != 0)
238 fatal("kex_prop2buf: %s", ssh_err(r)); 306 fatal("kex_prop2buf: %s", ssh_err(r));
239 307
@@ -330,6 +398,7 @@ static int input_gssapi_response(int type, u_int32_t, struct ssh *);
330static int input_gssapi_token(int type, u_int32_t, struct ssh *); 398static int input_gssapi_token(int type, u_int32_t, struct ssh *);
331static int input_gssapi_error(int, u_int32_t, struct ssh *); 399static int input_gssapi_error(int, u_int32_t, struct ssh *);
332static int input_gssapi_errtok(int, u_int32_t, struct ssh *); 400static int input_gssapi_errtok(int, u_int32_t, struct ssh *);
401static int userauth_gsskeyex(struct ssh *);
333#endif 402#endif
334 403
335void userauth(struct ssh *, char *); 404void userauth(struct ssh *, char *);
@@ -346,6 +415,11 @@ static char *authmethods_get(void);
346 415
347Authmethod authmethods[] = { 416Authmethod authmethods[] = {
348#ifdef GSSAPI 417#ifdef GSSAPI
418 {"gssapi-keyex",
419 userauth_gsskeyex,
420 NULL,
421 &options.gss_keyex,
422 NULL},
349 {"gssapi-with-mic", 423 {"gssapi-with-mic",
350 userauth_gssapi, 424 userauth_gssapi,
351 userauth_gssapi_cleanup, 425 userauth_gssapi_cleanup,
@@ -716,12 +790,31 @@ userauth_gssapi(struct ssh *ssh)
716 OM_uint32 min; 790 OM_uint32 min;
717 int r, ok = 0; 791 int r, ok = 0;
718 gss_OID mech = NULL; 792 gss_OID mech = NULL;
793 char *gss_host;
794
795 if (options.gss_server_identity) {
796 gss_host = xstrdup(options.gss_server_identity);
797 } else if (options.gss_trust_dns) {
798 gss_host = remote_hostname(ssh);
799 /* Fall back to specified host if we are using proxy command
800 * and can not use DNS on that socket */
801 if (strcmp(gss_host, "UNKNOWN") == 0) {
802 gss_host = authctxt->host;
803 }
804 } else {
805 gss_host = xstrdup(authctxt->host);
806 }
719 807
720 /* Try one GSSAPI method at a time, rather than sending them all at 808 /* Try one GSSAPI method at a time, rather than sending them all at
721 * once. */ 809 * once. */
722 810
723 if (authctxt->gss_supported_mechs == NULL) 811 if (authctxt->gss_supported_mechs == NULL)
724 gss_indicate_mechs(&min, &authctxt->gss_supported_mechs); 812 if (GSS_ERROR(gss_indicate_mechs(&min,
813 &authctxt->gss_supported_mechs))) {
814 authctxt->gss_supported_mechs = NULL;
815 free(gss_host);
816 return 0;
817 }
725 818
726 /* Check to see whether the mechanism is usable before we offer it */ 819 /* Check to see whether the mechanism is usable before we offer it */
727 while (authctxt->mech_tried < authctxt->gss_supported_mechs->count && 820 while (authctxt->mech_tried < authctxt->gss_supported_mechs->count &&
@@ -730,13 +823,15 @@ userauth_gssapi(struct ssh *ssh)
730 elements[authctxt->mech_tried]; 823 elements[authctxt->mech_tried];
731 /* My DER encoding requires length<128 */ 824 /* My DER encoding requires length<128 */
732 if (mech->length < 128 && ssh_gssapi_check_mechanism(&gssctxt, 825 if (mech->length < 128 && ssh_gssapi_check_mechanism(&gssctxt,
733 mech, authctxt->host)) { 826 mech, gss_host, options.gss_client_identity)) {
734 ok = 1; /* Mechanism works */ 827 ok = 1; /* Mechanism works */
735 } else { 828 } else {
736 authctxt->mech_tried++; 829 authctxt->mech_tried++;
737 } 830 }
738 } 831 }
739 832
833 free(gss_host);
834
740 if (!ok || mech == NULL) 835 if (!ok || mech == NULL)
741 return 0; 836 return 0;
742 837
@@ -976,6 +1071,55 @@ input_gssapi_error(int type, u_int32_t plen, struct ssh *ssh)
976 free(lang); 1071 free(lang);
977 return r; 1072 return r;
978} 1073}
1074
1075int
1076userauth_gsskeyex(struct ssh *ssh)
1077{
1078 struct sshbuf *b = NULL;
1079 Authctxt *authctxt = ssh->authctxt;
1080 gss_buffer_desc gssbuf;
1081 gss_buffer_desc mic = GSS_C_EMPTY_BUFFER;
1082 OM_uint32 ms;
1083 int r;
1084
1085 static int attempt = 0;
1086 if (attempt++ >= 1)
1087 return (0);
1088
1089 if (gss_kex_context == NULL) {
1090 debug("No valid Key exchange context");
1091 return (0);
1092 }
1093
1094 if ((b = sshbuf_new()) == NULL)
1095 fatal("%s: sshbuf_new failed", __func__);
1096
1097 ssh_gssapi_buildmic(b, authctxt->server_user, authctxt->service,
1098 "gssapi-keyex");
1099
1100 if ((gssbuf.value = sshbuf_mutable_ptr(b)) == NULL)
1101 fatal("%s: sshbuf_mutable_ptr failed", __func__);
1102 gssbuf.length = sshbuf_len(b);
1103
1104 if (GSS_ERROR(ssh_gssapi_sign(gss_kex_context, &gssbuf, &mic))) {
1105 sshbuf_free(b);
1106 return (0);
1107 }
1108
1109 if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_REQUEST)) != 0 ||
1110 (r = sshpkt_put_cstring(ssh, authctxt->server_user)) != 0 ||
1111 (r = sshpkt_put_cstring(ssh, authctxt->service)) != 0 ||
1112 (r = sshpkt_put_cstring(ssh, authctxt->method->name)) != 0 ||
1113 (r = sshpkt_put_string(ssh, mic.value, mic.length)) != 0 ||
1114 (r = sshpkt_send(ssh)) != 0)
1115 fatal("%s: %s", __func__, ssh_err(r));
1116
1117 sshbuf_free(b);
1118 gss_release_buffer(&ms, &mic);
1119
1120 return (1);
1121}
1122
979#endif /* GSSAPI */ 1123#endif /* GSSAPI */
980 1124
981static int 1125static int