diff options
Diffstat (limited to 'sshconnect2.c')
-rw-r--r-- | sshconnect2.c | 154 |
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 */ |
83 | extern char *client_version_string; | ||
84 | extern char *server_version_string; | ||
85 | extern Options options; | 83 | extern 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 *); | |||
330 | static int input_gssapi_token(int type, u_int32_t, struct ssh *); | 398 | static int input_gssapi_token(int type, u_int32_t, struct ssh *); |
331 | static int input_gssapi_error(int, u_int32_t, struct ssh *); | 399 | static int input_gssapi_error(int, u_int32_t, struct ssh *); |
332 | static int input_gssapi_errtok(int, u_int32_t, struct ssh *); | 400 | static int input_gssapi_errtok(int, u_int32_t, struct ssh *); |
401 | static int userauth_gsskeyex(struct ssh *); | ||
333 | #endif | 402 | #endif |
334 | 403 | ||
335 | void userauth(struct ssh *, char *); | 404 | void userauth(struct ssh *, char *); |
@@ -346,6 +415,11 @@ static char *authmethods_get(void); | |||
346 | 415 | ||
347 | Authmethod authmethods[] = { | 416 | Authmethod 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 | |||
1075 | int | ||
1076 | userauth_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 | ||
981 | static int | 1125 | static int |