diff options
Diffstat (limited to 'sshconnect2.c')
-rw-r--r-- | sshconnect2.c | 142 |
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 */ |
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,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 *); | |||
330 | static int input_gssapi_token(int type, u_int32_t, struct ssh *); | 392 | static int input_gssapi_token(int type, u_int32_t, struct ssh *); |
331 | static int input_gssapi_error(int, u_int32_t, struct ssh *); | 393 | static int input_gssapi_error(int, u_int32_t, struct ssh *); |
332 | static int input_gssapi_errtok(int, u_int32_t, struct ssh *); | 394 | static int input_gssapi_errtok(int, u_int32_t, struct ssh *); |
395 | static int userauth_gsskeyex(struct ssh *); | ||
333 | #endif | 396 | #endif |
334 | 397 | ||
335 | void userauth(struct ssh *, char *); | 398 | void userauth(struct ssh *, char *); |
@@ -346,6 +409,11 @@ static char *authmethods_get(void); | |||
346 | 409 | ||
347 | Authmethod authmethods[] = { | 410 | Authmethod 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 | |||
1063 | int | ||
1064 | userauth_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 | ||
981 | static int | 1113 | static int |