summaryrefslogtreecommitdiff
path: root/sshconnect2.c
diff options
context:
space:
mode:
Diffstat (limited to 'sshconnect2.c')
-rw-r--r--sshconnect2.c142
1 files changed, 137 insertions, 5 deletions
diff --git a/sshconnect2.c b/sshconnect2.c
index af00fb30c..03bc87eb4 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,35 @@ 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 else
223 gss_host = xstrdup(host);
224
225 gss = ssh_gssapi_client_mechanisms(gss_host,
226 options.gss_client_identity, options.gss_kex_algorithms);
227 if (gss) {
228 debug("Offering GSSAPI proposal: %s", gss);
229 xasprintf(&myproposal[PROPOSAL_KEX_ALGS],
230 "%s,%s", gss, orig);
231
232 /* If we've got GSSAPI algorithms, then we also support the
233 * 'null' hostkey, as a last resort */
234 orig = myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS];
235 xasprintf(&myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS],
236 "%s,null", orig);
237 }
238 }
239#endif
240
209 if (options.rekey_limit || options.rekey_interval) 241 if (options.rekey_limit || options.rekey_interval)
210 ssh_packet_set_rekey_limits(ssh, options.rekey_limit, 242 ssh_packet_set_rekey_limits(ssh, options.rekey_limit,
211 options.rekey_interval); 243 options.rekey_interval);
@@ -224,16 +256,46 @@ ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port)
224# ifdef OPENSSL_HAS_ECC 256# ifdef OPENSSL_HAS_ECC
225 ssh->kex->kex[KEX_ECDH_SHA2] = kex_gen_client; 257 ssh->kex->kex[KEX_ECDH_SHA2] = kex_gen_client;
226# endif 258# endif
227#endif 259# ifdef GSSAPI
260 if (options.gss_keyex) {
261 ssh->kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_client;
262 ssh->kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_client;
263 ssh->kex->kex[KEX_GSS_GRP14_SHA256] = kexgss_client;
264 ssh->kex->kex[KEX_GSS_GRP16_SHA512] = kexgss_client;
265 ssh->kex->kex[KEX_GSS_GEX_SHA1] = kexgssgex_client;
266 ssh->kex->kex[KEX_GSS_NISTP256_SHA256] = kexgss_client;
267 ssh->kex->kex[KEX_GSS_C25519_SHA256] = kexgss_client;
268 }
269# endif
270#endif /* WITH_OPENSSL */
228 ssh->kex->kex[KEX_C25519_SHA256] = kex_gen_client; 271 ssh->kex->kex[KEX_C25519_SHA256] = kex_gen_client;
229 ssh->kex->kex[KEX_KEM_SNTRUP4591761X25519_SHA512] = kex_gen_client; 272 ssh->kex->kex[KEX_KEM_SNTRUP4591761X25519_SHA512] = kex_gen_client;
230 ssh->kex->verify_host_key=&verify_host_key_callback; 273 ssh->kex->verify_host_key=&verify_host_key_callback;
231 274
275#if defined(GSSAPI) && defined(WITH_OPENSSL)
276 if (options.gss_keyex) {
277 ssh->kex->gss_deleg_creds = options.gss_deleg_creds;
278 ssh->kex->gss_trust_dns = options.gss_trust_dns;
279 ssh->kex->gss_client = options.gss_client_identity;
280 ssh->kex->gss_host = gss_host;
281 }
282#endif
283
232 ssh_dispatch_run_fatal(ssh, DISPATCH_BLOCK, &ssh->kex->done); 284 ssh_dispatch_run_fatal(ssh, DISPATCH_BLOCK, &ssh->kex->done);
233 285
234 /* remove ext-info from the KEX proposals for rekeying */ 286 /* remove ext-info from the KEX proposals for rekeying */
235 myproposal[PROPOSAL_KEX_ALGS] = 287 myproposal[PROPOSAL_KEX_ALGS] =
236 compat_kex_proposal(options.kex_algorithms); 288 compat_kex_proposal(options.kex_algorithms);
289#if defined(GSSAPI) && defined(WITH_OPENSSL)
290 /* repair myproposal after it was crumpled by the */
291 /* ext-info removal above */
292 if (gss) {
293 orig = myproposal[PROPOSAL_KEX_ALGS];
294 xasprintf(&myproposal[PROPOSAL_KEX_ALGS],
295 "%s,%s", gss, orig);
296 free(gss);
297 }
298#endif
237 if ((r = kex_prop2buf(ssh->kex->my, myproposal)) != 0) 299 if ((r = kex_prop2buf(ssh->kex->my, myproposal)) != 0)
238 fatal("kex_prop2buf: %s", ssh_err(r)); 300 fatal("kex_prop2buf: %s", ssh_err(r));
239 301
@@ -330,6 +392,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 *); 392static int input_gssapi_token(int type, u_int32_t, struct ssh *);
331static int input_gssapi_error(int, u_int32_t, struct ssh *); 393static int input_gssapi_error(int, u_int32_t, struct ssh *);
332static int input_gssapi_errtok(int, u_int32_t, struct ssh *); 394static int input_gssapi_errtok(int, u_int32_t, struct ssh *);
395static int userauth_gsskeyex(struct ssh *);
333#endif 396#endif
334 397
335void userauth(struct ssh *, char *); 398void userauth(struct ssh *, char *);
@@ -346,6 +409,11 @@ static char *authmethods_get(void);
346 409
347Authmethod authmethods[] = { 410Authmethod authmethods[] = {
348#ifdef GSSAPI 411#ifdef GSSAPI
412 {"gssapi-keyex",
413 userauth_gsskeyex,
414 NULL,
415 &options.gss_keyex,
416 NULL},
349 {"gssapi-with-mic", 417 {"gssapi-with-mic",
350 userauth_gssapi, 418 userauth_gssapi,
351 userauth_gssapi_cleanup, 419 userauth_gssapi_cleanup,
@@ -716,12 +784,25 @@ userauth_gssapi(struct ssh *ssh)
716 OM_uint32 min; 784 OM_uint32 min;
717 int r, ok = 0; 785 int r, ok = 0;
718 gss_OID mech = NULL; 786 gss_OID mech = NULL;
787 char *gss_host;
788
789 if (options.gss_server_identity)
790 gss_host = xstrdup(options.gss_server_identity);
791 else if (options.gss_trust_dns)
792 gss_host = remote_hostname(ssh);
793 else
794 gss_host = xstrdup(authctxt->host);
719 795
720 /* Try one GSSAPI method at a time, rather than sending them all at 796 /* Try one GSSAPI method at a time, rather than sending them all at
721 * once. */ 797 * once. */
722 798
723 if (authctxt->gss_supported_mechs == NULL) 799 if (authctxt->gss_supported_mechs == NULL)
724 gss_indicate_mechs(&min, &authctxt->gss_supported_mechs); 800 if (GSS_ERROR(gss_indicate_mechs(&min,
801 &authctxt->gss_supported_mechs))) {
802 authctxt->gss_supported_mechs = NULL;
803 free(gss_host);
804 return 0;
805 }
725 806
726 /* Check to see whether the mechanism is usable before we offer it */ 807 /* Check to see whether the mechanism is usable before we offer it */
727 while (authctxt->mech_tried < authctxt->gss_supported_mechs->count && 808 while (authctxt->mech_tried < authctxt->gss_supported_mechs->count &&
@@ -730,13 +811,15 @@ userauth_gssapi(struct ssh *ssh)
730 elements[authctxt->mech_tried]; 811 elements[authctxt->mech_tried];
731 /* My DER encoding requires length<128 */ 812 /* My DER encoding requires length<128 */
732 if (mech->length < 128 && ssh_gssapi_check_mechanism(&gssctxt, 813 if (mech->length < 128 && ssh_gssapi_check_mechanism(&gssctxt,
733 mech, authctxt->host)) { 814 mech, gss_host, options.gss_client_identity)) {
734 ok = 1; /* Mechanism works */ 815 ok = 1; /* Mechanism works */
735 } else { 816 } else {
736 authctxt->mech_tried++; 817 authctxt->mech_tried++;
737 } 818 }
738 } 819 }
739 820
821 free(gss_host);
822
740 if (!ok || mech == NULL) 823 if (!ok || mech == NULL)
741 return 0; 824 return 0;
742 825
@@ -976,6 +1059,55 @@ input_gssapi_error(int type, u_int32_t plen, struct ssh *ssh)
976 free(lang); 1059 free(lang);
977 return r; 1060 return r;
978} 1061}
1062
1063int
1064userauth_gsskeyex(struct ssh *ssh)
1065{
1066 struct sshbuf *b = NULL;
1067 Authctxt *authctxt = ssh->authctxt;
1068 gss_buffer_desc gssbuf;
1069 gss_buffer_desc mic = GSS_C_EMPTY_BUFFER;
1070 OM_uint32 ms;
1071 int r;
1072
1073 static int attempt = 0;
1074 if (attempt++ >= 1)
1075 return (0);
1076
1077 if (gss_kex_context == NULL) {
1078 debug("No valid Key exchange context");
1079 return (0);
1080 }
1081
1082 if ((b = sshbuf_new()) == NULL)
1083 fatal("%s: sshbuf_new failed", __func__);
1084
1085 ssh_gssapi_buildmic(b, authctxt->server_user, authctxt->service,
1086 "gssapi-keyex");
1087
1088 if ((gssbuf.value = sshbuf_mutable_ptr(b)) == NULL)
1089 fatal("%s: sshbuf_mutable_ptr failed", __func__);
1090 gssbuf.length = sshbuf_len(b);
1091
1092 if (GSS_ERROR(ssh_gssapi_sign(gss_kex_context, &gssbuf, &mic))) {
1093 sshbuf_free(b);
1094 return (0);
1095 }
1096
1097 if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_REQUEST)) != 0 ||
1098 (r = sshpkt_put_cstring(ssh, authctxt->server_user)) != 0 ||
1099 (r = sshpkt_put_cstring(ssh, authctxt->service)) != 0 ||
1100 (r = sshpkt_put_cstring(ssh, authctxt->method->name)) != 0 ||
1101 (r = sshpkt_put_string(ssh, mic.value, mic.length)) != 0 ||
1102 (r = sshpkt_send(ssh)) != 0)
1103 fatal("%s: %s", __func__, ssh_err(r));
1104
1105 sshbuf_free(b);
1106 gss_release_buffer(&ms, &mic);
1107
1108 return (1);
1109}
1110
979#endif /* GSSAPI */ 1111#endif /* GSSAPI */
980 1112
981static int 1113static int