diff options
Diffstat (limited to 'sshconnect2.c')
-rw-r--r-- | sshconnect2.c | 140 |
1 files changed, 136 insertions, 4 deletions
diff --git a/sshconnect2.c b/sshconnect2.c index 87fa70a40..a4ec75ca1 100644 --- a/sshconnect2.c +++ b/sshconnect2.c | |||
@@ -78,8 +78,6 @@ | |||
78 | #endif | 78 | #endif |
79 | 79 | ||
80 | /* import */ | 80 | /* import */ |
81 | extern char *client_version_string; | ||
82 | extern char *server_version_string; | ||
83 | extern Options options; | 81 | extern Options options; |
84 | 82 | ||
85 | /* | 83 | /* |
@@ -161,6 +159,11 @@ ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port) | |||
161 | char *s, *all_key; | 159 | char *s, *all_key; |
162 | int r; | 160 | int r; |
163 | 161 | ||
162 | #if defined(GSSAPI) && defined(WITH_OPENSSL) | ||
163 | char *orig = NULL, *gss = NULL; | ||
164 | char *gss_host = NULL; | ||
165 | #endif | ||
166 | |||
164 | xxx_host = host; | 167 | xxx_host = host; |
165 | xxx_hostaddr = hostaddr; | 168 | xxx_hostaddr = hostaddr; |
166 | 169 | ||
@@ -193,6 +196,35 @@ ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port) | |||
193 | order_hostkeyalgs(host, hostaddr, port)); | 196 | order_hostkeyalgs(host, hostaddr, port)); |
194 | } | 197 | } |
195 | 198 | ||
199 | #if defined(GSSAPI) && defined(WITH_OPENSSL) | ||
200 | if (options.gss_keyex) { | ||
201 | /* Add the GSSAPI mechanisms currently supported on this | ||
202 | * client to the key exchange algorithm proposal */ | ||
203 | orig = myproposal[PROPOSAL_KEX_ALGS]; | ||
204 | |||
205 | if (options.gss_server_identity) | ||
206 | gss_host = xstrdup(options.gss_server_identity); | ||
207 | else if (options.gss_trust_dns) | ||
208 | gss_host = remote_hostname(ssh); | ||
209 | else | ||
210 | gss_host = xstrdup(host); | ||
211 | |||
212 | gss = ssh_gssapi_client_mechanisms(gss_host, | ||
213 | options.gss_client_identity, options.gss_kex_algorithms); | ||
214 | if (gss) { | ||
215 | debug("Offering GSSAPI proposal: %s", gss); | ||
216 | xasprintf(&myproposal[PROPOSAL_KEX_ALGS], | ||
217 | "%s,%s", gss, orig); | ||
218 | |||
219 | /* If we've got GSSAPI algorithms, then we also support the | ||
220 | * 'null' hostkey, as a last resort */ | ||
221 | orig = myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]; | ||
222 | xasprintf(&myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS], | ||
223 | "%s,null", orig); | ||
224 | } | ||
225 | } | ||
226 | #endif | ||
227 | |||
196 | if (options.rekey_limit || options.rekey_interval) | 228 | if (options.rekey_limit || options.rekey_interval) |
197 | ssh_packet_set_rekey_limits(ssh, options.rekey_limit, | 229 | ssh_packet_set_rekey_limits(ssh, options.rekey_limit, |
198 | options.rekey_interval); | 230 | options.rekey_interval); |
@@ -211,16 +243,46 @@ ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port) | |||
211 | # ifdef OPENSSL_HAS_ECC | 243 | # ifdef OPENSSL_HAS_ECC |
212 | ssh->kex->kex[KEX_ECDH_SHA2] = kex_gen_client; | 244 | ssh->kex->kex[KEX_ECDH_SHA2] = kex_gen_client; |
213 | # endif | 245 | # endif |
246 | # ifdef GSSAPI | ||
247 | if (options.gss_keyex) { | ||
248 | ssh->kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_client; | ||
249 | ssh->kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_client; | ||
250 | ssh->kex->kex[KEX_GSS_GRP14_SHA256] = kexgss_client; | ||
251 | ssh->kex->kex[KEX_GSS_GRP16_SHA512] = kexgss_client; | ||
252 | ssh->kex->kex[KEX_GSS_GEX_SHA1] = kexgssgex_client; | ||
253 | ssh->kex->kex[KEX_GSS_NISTP256_SHA256] = kexgss_client; | ||
254 | ssh->kex->kex[KEX_GSS_C25519_SHA256] = kexgss_client; | ||
255 | } | ||
256 | # endif | ||
214 | #endif | 257 | #endif |
215 | ssh->kex->kex[KEX_C25519_SHA256] = kex_gen_client; | 258 | ssh->kex->kex[KEX_C25519_SHA256] = kex_gen_client; |
216 | ssh->kex->kex[KEX_KEM_SNTRUP4591761X25519_SHA512] = kex_gen_client; | 259 | ssh->kex->kex[KEX_KEM_SNTRUP4591761X25519_SHA512] = kex_gen_client; |
217 | ssh->kex->verify_host_key=&verify_host_key_callback; | 260 | ssh->kex->verify_host_key=&verify_host_key_callback; |
218 | 261 | ||
262 | #if defined(GSSAPI) && defined(WITH_OPENSSL) | ||
263 | if (options.gss_keyex) { | ||
264 | ssh->kex->gss_deleg_creds = options.gss_deleg_creds; | ||
265 | ssh->kex->gss_trust_dns = options.gss_trust_dns; | ||
266 | ssh->kex->gss_client = options.gss_client_identity; | ||
267 | ssh->kex->gss_host = gss_host; | ||
268 | } | ||
269 | #endif | ||
270 | |||
219 | ssh_dispatch_run_fatal(ssh, DISPATCH_BLOCK, &ssh->kex->done); | 271 | ssh_dispatch_run_fatal(ssh, DISPATCH_BLOCK, &ssh->kex->done); |
220 | 272 | ||
221 | /* remove ext-info from the KEX proposals for rekeying */ | 273 | /* remove ext-info from the KEX proposals for rekeying */ |
222 | myproposal[PROPOSAL_KEX_ALGS] = | 274 | myproposal[PROPOSAL_KEX_ALGS] = |
223 | compat_kex_proposal(options.kex_algorithms); | 275 | compat_kex_proposal(options.kex_algorithms); |
276 | #if defined(GSSAPI) && defined(WITH_OPENSSL) | ||
277 | /* repair myproposal after it was crumpled by the */ | ||
278 | /* ext-info removal above */ | ||
279 | if (gss) { | ||
280 | orig = myproposal[PROPOSAL_KEX_ALGS]; | ||
281 | xasprintf(&myproposal[PROPOSAL_KEX_ALGS], | ||
282 | "%s,%s", gss, orig); | ||
283 | free(gss); | ||
284 | } | ||
285 | #endif | ||
224 | if ((r = kex_prop2buf(ssh->kex->my, myproposal)) != 0) | 286 | if ((r = kex_prop2buf(ssh->kex->my, myproposal)) != 0) |
225 | fatal("kex_prop2buf: %s", ssh_err(r)); | 287 | fatal("kex_prop2buf: %s", ssh_err(r)); |
226 | 288 | ||
@@ -317,6 +379,7 @@ static int input_gssapi_response(int type, u_int32_t, struct ssh *); | |||
317 | static int input_gssapi_token(int type, u_int32_t, struct ssh *); | 379 | static int input_gssapi_token(int type, u_int32_t, struct ssh *); |
318 | static int input_gssapi_error(int, u_int32_t, struct ssh *); | 380 | static int input_gssapi_error(int, u_int32_t, struct ssh *); |
319 | static int input_gssapi_errtok(int, u_int32_t, struct ssh *); | 381 | static int input_gssapi_errtok(int, u_int32_t, struct ssh *); |
382 | static int userauth_gsskeyex(struct ssh *); | ||
320 | #endif | 383 | #endif |
321 | 384 | ||
322 | void userauth(struct ssh *, char *); | 385 | void userauth(struct ssh *, char *); |
@@ -333,6 +396,11 @@ static char *authmethods_get(void); | |||
333 | 396 | ||
334 | Authmethod authmethods[] = { | 397 | Authmethod authmethods[] = { |
335 | #ifdef GSSAPI | 398 | #ifdef GSSAPI |
399 | {"gssapi-keyex", | ||
400 | userauth_gsskeyex, | ||
401 | NULL, | ||
402 | &options.gss_keyex, | ||
403 | NULL}, | ||
336 | {"gssapi-with-mic", | 404 | {"gssapi-with-mic", |
337 | userauth_gssapi, | 405 | userauth_gssapi, |
338 | userauth_gssapi_cleanup, | 406 | userauth_gssapi_cleanup, |
@@ -697,12 +765,25 @@ userauth_gssapi(struct ssh *ssh) | |||
697 | OM_uint32 min; | 765 | OM_uint32 min; |
698 | int r, ok = 0; | 766 | int r, ok = 0; |
699 | gss_OID mech = NULL; | 767 | gss_OID mech = NULL; |
768 | char *gss_host; | ||
769 | |||
770 | if (options.gss_server_identity) | ||
771 | gss_host = xstrdup(options.gss_server_identity); | ||
772 | else if (options.gss_trust_dns) | ||
773 | gss_host = remote_hostname(ssh); | ||
774 | else | ||
775 | gss_host = xstrdup(authctxt->host); | ||
700 | 776 | ||
701 | /* Try one GSSAPI method at a time, rather than sending them all at | 777 | /* Try one GSSAPI method at a time, rather than sending them all at |
702 | * once. */ | 778 | * once. */ |
703 | 779 | ||
704 | if (authctxt->gss_supported_mechs == NULL) | 780 | if (authctxt->gss_supported_mechs == NULL) |
705 | gss_indicate_mechs(&min, &authctxt->gss_supported_mechs); | 781 | if (GSS_ERROR(gss_indicate_mechs(&min, |
782 | &authctxt->gss_supported_mechs))) { | ||
783 | authctxt->gss_supported_mechs = NULL; | ||
784 | free(gss_host); | ||
785 | return 0; | ||
786 | } | ||
706 | 787 | ||
707 | /* Check to see whether the mechanism is usable before we offer it */ | 788 | /* Check to see whether the mechanism is usable before we offer it */ |
708 | while (authctxt->mech_tried < authctxt->gss_supported_mechs->count && | 789 | while (authctxt->mech_tried < authctxt->gss_supported_mechs->count && |
@@ -711,13 +792,15 @@ userauth_gssapi(struct ssh *ssh) | |||
711 | elements[authctxt->mech_tried]; | 792 | elements[authctxt->mech_tried]; |
712 | /* My DER encoding requires length<128 */ | 793 | /* My DER encoding requires length<128 */ |
713 | if (mech->length < 128 && ssh_gssapi_check_mechanism(&gssctxt, | 794 | if (mech->length < 128 && ssh_gssapi_check_mechanism(&gssctxt, |
714 | mech, authctxt->host)) { | 795 | mech, gss_host, options.gss_client_identity)) { |
715 | ok = 1; /* Mechanism works */ | 796 | ok = 1; /* Mechanism works */ |
716 | } else { | 797 | } else { |
717 | authctxt->mech_tried++; | 798 | authctxt->mech_tried++; |
718 | } | 799 | } |
719 | } | 800 | } |
720 | 801 | ||
802 | free(gss_host); | ||
803 | |||
721 | if (!ok || mech == NULL) | 804 | if (!ok || mech == NULL) |
722 | return 0; | 805 | return 0; |
723 | 806 | ||
@@ -957,6 +1040,55 @@ input_gssapi_error(int type, u_int32_t plen, struct ssh *ssh) | |||
957 | free(lang); | 1040 | free(lang); |
958 | return r; | 1041 | return r; |
959 | } | 1042 | } |
1043 | |||
1044 | int | ||
1045 | userauth_gsskeyex(struct ssh *ssh) | ||
1046 | { | ||
1047 | struct sshbuf *b = NULL; | ||
1048 | Authctxt *authctxt = ssh->authctxt; | ||
1049 | gss_buffer_desc gssbuf; | ||
1050 | gss_buffer_desc mic = GSS_C_EMPTY_BUFFER; | ||
1051 | OM_uint32 ms; | ||
1052 | int r; | ||
1053 | |||
1054 | static int attempt = 0; | ||
1055 | if (attempt++ >= 1) | ||
1056 | return (0); | ||
1057 | |||
1058 | if (gss_kex_context == NULL) { | ||
1059 | debug("No valid Key exchange context"); | ||
1060 | return (0); | ||
1061 | } | ||
1062 | |||
1063 | if ((b = sshbuf_new()) == NULL) | ||
1064 | fatal("%s: sshbuf_new failed", __func__); | ||
1065 | |||
1066 | ssh_gssapi_buildmic(b, authctxt->server_user, authctxt->service, | ||
1067 | "gssapi-keyex"); | ||
1068 | |||
1069 | if ((gssbuf.value = sshbuf_mutable_ptr(b)) == NULL) | ||
1070 | fatal("%s: sshbuf_mutable_ptr failed", __func__); | ||
1071 | gssbuf.length = sshbuf_len(b); | ||
1072 | |||
1073 | if (GSS_ERROR(ssh_gssapi_sign(gss_kex_context, &gssbuf, &mic))) { | ||
1074 | sshbuf_free(b); | ||
1075 | return (0); | ||
1076 | } | ||
1077 | |||
1078 | if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_REQUEST)) != 0 || | ||
1079 | (r = sshpkt_put_cstring(ssh, authctxt->server_user)) != 0 || | ||
1080 | (r = sshpkt_put_cstring(ssh, authctxt->service)) != 0 || | ||
1081 | (r = sshpkt_put_cstring(ssh, authctxt->method->name)) != 0 || | ||
1082 | (r = sshpkt_put_string(ssh, mic.value, mic.length)) != 0 || | ||
1083 | (r = sshpkt_send(ssh)) != 0) | ||
1084 | fatal("%s: %s", __func__, ssh_err(r)); | ||
1085 | |||
1086 | sshbuf_free(b); | ||
1087 | gss_release_buffer(&ms, &mic); | ||
1088 | |||
1089 | return (1); | ||
1090 | } | ||
1091 | |||
960 | #endif /* GSSAPI */ | 1092 | #endif /* GSSAPI */ |
961 | 1093 | ||
962 | static int | 1094 | static int |