diff options
author | Colin Watson <cjwatson@debian.org> | 2010-01-01 23:53:30 +0000 |
---|---|---|
committer | Colin Watson <cjwatson@debian.org> | 2010-01-01 23:53:30 +0000 |
commit | df03186a4f9e0c2ece398b5c0571cb6263d7a752 (patch) | |
tree | 1aab079441dff9615274769b19f2d734ddf508dd /sshconnect2.c | |
parent | 6ad6994c288662fca6949f42bf91fec2aff00bca (diff) | |
parent | 99b402ea4c8457b0a3cafff37f5b3410a8dc6476 (diff) |
* New upstream release (closes: #536182). Yes, I know 5.3p1 has been out
for a while, but there's no GSSAPI patch available for it yet.
- Change the default cipher order to prefer the AES CTR modes and the
revised "arcfour256" mode to CBC mode ciphers that are susceptible to
CPNI-957037 "Plaintext Recovery Attack Against SSH".
- Add countermeasures to mitigate CPNI-957037-style attacks against the
SSH protocol's use of CBC-mode ciphers. Upon detection of an invalid
packet length or Message Authentication Code, ssh/sshd will continue
reading up to the maximum supported packet length rather than
immediately terminating the connection. This eliminates most of the
known differences in behaviour that leaked information about the
plaintext of injected data which formed the basis of this attack
(closes: #506115, LP: #379329).
- ForceCommand directive now accepts commandline arguments for the
internal-sftp server (closes: #524423, LP: #362511).
- Add AllowAgentForwarding to available Match keywords list (closes:
#540623).
- Make ssh(1) send the correct channel number for
SSH2_MSG_CHANNEL_SUCCESS and SSH2_MSG_CHANNEL_FAILURE messages to
avoid triggering 'Non-public channel' error messages on sshd(8) in
openssh-5.1.
- Avoid printing 'Non-public channel' warnings in sshd(8), since the
ssh(1) has sent incorrect channel numbers since ~2004 (this reverts a
behaviour introduced in openssh-5.1; closes: #496017).
* Update to GSSAPI patch from
http://www.sxw.org.uk/computing/patches/openssh-5.2p1-gsskex-all-20090726.patch,
including cascading credentials support (LP: #416958).
Diffstat (limited to 'sshconnect2.c')
-rw-r--r-- | sshconnect2.c | 353 |
1 files changed, 336 insertions, 17 deletions
diff --git a/sshconnect2.c b/sshconnect2.c index 185e7b204..bb72db5dd 100644 --- a/sshconnect2.c +++ b/sshconnect2.c | |||
@@ -1,6 +1,7 @@ | |||
1 | /* $OpenBSD: sshconnect2.c,v 1.166 2008/07/17 08:48:00 djm Exp $ */ | 1 | /* $OpenBSD: sshconnect2.c,v 1.170 2008/11/04 08:22:13 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. |
4 | * Copyright (c) 2008 Damien Miller. All rights reserved. | ||
4 | * | 5 | * |
5 | * Redistribution and use in source and binary forms, with or without | 6 | * Redistribution and use in source and binary forms, with or without |
6 | * modification, are permitted provided that the following conditions | 7 | * modification, are permitted provided that the following conditions |
@@ -67,6 +68,7 @@ | |||
67 | #include "msg.h" | 68 | #include "msg.h" |
68 | #include "pathnames.h" | 69 | #include "pathnames.h" |
69 | #include "uidswap.h" | 70 | #include "uidswap.h" |
71 | #include "jpake.h" | ||
70 | 72 | ||
71 | #ifdef GSSAPI | 73 | #ifdef GSSAPI |
72 | #include "ssh-gss.h" | 74 | #include "ssh-gss.h" |
@@ -121,7 +123,7 @@ ssh_kex2(char *host, struct sockaddr *hostaddr) | |||
121 | else | 123 | else |
122 | gss_host = host; | 124 | gss_host = host; |
123 | 125 | ||
124 | gss = ssh_gssapi_client_mechanisms(gss_host); | 126 | gss = ssh_gssapi_client_mechanisms(gss_host, options.gss_client_identity); |
125 | if (gss) { | 127 | if (gss) { |
126 | debug("Offering GSSAPI proposal: %s", gss); | 128 | debug("Offering GSSAPI proposal: %s", gss); |
127 | xasprintf(&myproposal[PROPOSAL_KEX_ALGS], | 129 | xasprintf(&myproposal[PROPOSAL_KEX_ALGS], |
@@ -164,6 +166,7 @@ ssh_kex2(char *host, struct sockaddr *hostaddr) | |||
164 | orig = myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]; | 166 | orig = myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]; |
165 | xasprintf(&myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS], | 167 | xasprintf(&myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS], |
166 | "%s,null", orig); | 168 | "%s,null", orig); |
169 | xfree(gss); | ||
167 | } | 170 | } |
168 | #endif | 171 | #endif |
169 | 172 | ||
@@ -177,18 +180,23 @@ ssh_kex2(char *host, struct sockaddr *hostaddr) | |||
177 | kex->kex[KEX_DH_GEX_SHA1] = kexgex_client; | 180 | kex->kex[KEX_DH_GEX_SHA1] = kexgex_client; |
178 | kex->kex[KEX_DH_GEX_SHA256] = kexgex_client; | 181 | kex->kex[KEX_DH_GEX_SHA256] = kexgex_client; |
179 | #ifdef GSSAPI | 182 | #ifdef GSSAPI |
180 | kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_client; | 183 | if (options.gss_keyex) { |
181 | kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_client; | 184 | kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_client; |
182 | kex->kex[KEX_GSS_GEX_SHA1] = kexgss_client; | 185 | kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_client; |
186 | kex->kex[KEX_GSS_GEX_SHA1] = kexgss_client; | ||
187 | } | ||
183 | #endif | 188 | #endif |
184 | kex->client_version_string=client_version_string; | 189 | kex->client_version_string=client_version_string; |
185 | kex->server_version_string=server_version_string; | 190 | kex->server_version_string=server_version_string; |
186 | kex->verify_host_key=&verify_host_key_callback; | 191 | kex->verify_host_key=&verify_host_key_callback; |
187 | 192 | ||
188 | #ifdef GSSAPI | 193 | #ifdef GSSAPI |
189 | kex->gss_deleg_creds = options.gss_deleg_creds; | 194 | if (options.gss_keyex) { |
190 | kex->gss_trust_dns = options.gss_trust_dns; | 195 | kex->gss_deleg_creds = options.gss_deleg_creds; |
191 | kex->gss_host = gss_host; | 196 | kex->gss_trust_dns = options.gss_trust_dns; |
197 | kex->gss_client = options.gss_client_identity; | ||
198 | kex->gss_host = gss_host; | ||
199 | } | ||
192 | #endif | 200 | #endif |
193 | 201 | ||
194 | xxx_kex = kex; | 202 | xxx_kex = kex; |
@@ -247,6 +255,7 @@ struct Authctxt { | |||
247 | struct Authmethod { | 255 | struct Authmethod { |
248 | char *name; /* string to compare against server's list */ | 256 | char *name; /* string to compare against server's list */ |
249 | int (*userauth)(Authctxt *authctxt); | 257 | int (*userauth)(Authctxt *authctxt); |
258 | void (*cleanup)(Authctxt *authctxt); | ||
250 | int *enabled; /* flag in option struct that enables method */ | 259 | int *enabled; /* flag in option struct that enables method */ |
251 | int *batch_flag; /* flag in option struct that disables method */ | 260 | int *batch_flag; /* flag in option struct that disables method */ |
252 | }; | 261 | }; |
@@ -258,13 +267,18 @@ void input_userauth_error(int, u_int32_t, void *); | |||
258 | void input_userauth_info_req(int, u_int32_t, void *); | 267 | void input_userauth_info_req(int, u_int32_t, void *); |
259 | void input_userauth_pk_ok(int, u_int32_t, void *); | 268 | void input_userauth_pk_ok(int, u_int32_t, void *); |
260 | void input_userauth_passwd_changereq(int, u_int32_t, void *); | 269 | void input_userauth_passwd_changereq(int, u_int32_t, void *); |
270 | void input_userauth_jpake_server_step1(int, u_int32_t, void *); | ||
271 | void input_userauth_jpake_server_step2(int, u_int32_t, void *); | ||
272 | void input_userauth_jpake_server_confirm(int, u_int32_t, void *); | ||
261 | 273 | ||
262 | int userauth_none(Authctxt *); | 274 | int userauth_none(Authctxt *); |
263 | int userauth_pubkey(Authctxt *); | 275 | int userauth_pubkey(Authctxt *); |
264 | int userauth_passwd(Authctxt *); | 276 | int userauth_passwd(Authctxt *); |
265 | int userauth_kbdint(Authctxt *); | 277 | int userauth_kbdint(Authctxt *); |
266 | int userauth_hostbased(Authctxt *); | 278 | int userauth_hostbased(Authctxt *); |
267 | int userauth_kerberos(Authctxt *); | 279 | int userauth_jpake(Authctxt *); |
280 | |||
281 | void userauth_jpake_cleanup(Authctxt *); | ||
268 | 282 | ||
269 | #ifdef GSSAPI | 283 | #ifdef GSSAPI |
270 | int userauth_gssapi(Authctxt *authctxt); | 284 | int userauth_gssapi(Authctxt *authctxt); |
@@ -295,6 +309,7 @@ Authmethod authmethods[] = { | |||
295 | NULL}, | 309 | NULL}, |
296 | {"gssapi-with-mic", | 310 | {"gssapi-with-mic", |
297 | userauth_gssapi, | 311 | userauth_gssapi, |
312 | NULL, | ||
298 | &options.gss_authentication, | 313 | &options.gss_authentication, |
299 | NULL}, | 314 | NULL}, |
300 | {"gssapi", | 315 | {"gssapi", |
@@ -304,25 +319,37 @@ Authmethod authmethods[] = { | |||
304 | #endif | 319 | #endif |
305 | {"hostbased", | 320 | {"hostbased", |
306 | userauth_hostbased, | 321 | userauth_hostbased, |
322 | NULL, | ||
307 | &options.hostbased_authentication, | 323 | &options.hostbased_authentication, |
308 | NULL}, | 324 | NULL}, |
309 | {"publickey", | 325 | {"publickey", |
310 | userauth_pubkey, | 326 | userauth_pubkey, |
327 | NULL, | ||
311 | &options.pubkey_authentication, | 328 | &options.pubkey_authentication, |
312 | NULL}, | 329 | NULL}, |
330 | #ifdef JPAKE | ||
331 | {"jpake-01@openssh.com", | ||
332 | userauth_jpake, | ||
333 | userauth_jpake_cleanup, | ||
334 | &options.zero_knowledge_password_authentication, | ||
335 | &options.batch_mode}, | ||
336 | #endif | ||
313 | {"keyboard-interactive", | 337 | {"keyboard-interactive", |
314 | userauth_kbdint, | 338 | userauth_kbdint, |
339 | NULL, | ||
315 | &options.kbd_interactive_authentication, | 340 | &options.kbd_interactive_authentication, |
316 | &options.batch_mode}, | 341 | &options.batch_mode}, |
317 | {"password", | 342 | {"password", |
318 | userauth_passwd, | 343 | userauth_passwd, |
344 | NULL, | ||
319 | &options.password_authentication, | 345 | &options.password_authentication, |
320 | &options.batch_mode}, | 346 | &options.batch_mode}, |
321 | {"none", | 347 | {"none", |
322 | userauth_none, | 348 | userauth_none, |
323 | NULL, | 349 | NULL, |
350 | NULL, | ||
324 | NULL}, | 351 | NULL}, |
325 | {NULL, NULL, NULL, NULL} | 352 | {NULL, NULL, NULL, NULL, NULL} |
326 | }; | 353 | }; |
327 | 354 | ||
328 | void | 355 | void |
@@ -390,6 +417,9 @@ ssh_userauth2(const char *local_user, const char *server_user, char *host, | |||
390 | void | 417 | void |
391 | userauth(Authctxt *authctxt, char *authlist) | 418 | userauth(Authctxt *authctxt, char *authlist) |
392 | { | 419 | { |
420 | if (authctxt->method != NULL && authctxt->method->cleanup != NULL) | ||
421 | authctxt->method->cleanup(authctxt); | ||
422 | |||
393 | if (authctxt->methoddata) { | 423 | if (authctxt->methoddata) { |
394 | xfree(authctxt->methoddata); | 424 | xfree(authctxt->methoddata); |
395 | authctxt->methoddata = NULL; | 425 | authctxt->methoddata = NULL; |
@@ -422,6 +452,7 @@ userauth(Authctxt *authctxt, char *authlist) | |||
422 | } | 452 | } |
423 | } | 453 | } |
424 | 454 | ||
455 | /* ARGSUSED */ | ||
425 | void | 456 | void |
426 | input_userauth_error(int type, u_int32_t seq, void *ctxt) | 457 | input_userauth_error(int type, u_int32_t seq, void *ctxt) |
427 | { | 458 | { |
@@ -429,6 +460,7 @@ input_userauth_error(int type, u_int32_t seq, void *ctxt) | |||
429 | "type %d", type); | 460 | "type %d", type); |
430 | } | 461 | } |
431 | 462 | ||
463 | /* ARGSUSED */ | ||
432 | void | 464 | void |
433 | input_userauth_banner(int type, u_int32_t seq, void *ctxt) | 465 | input_userauth_banner(int type, u_int32_t seq, void *ctxt) |
434 | { | 466 | { |
@@ -438,12 +470,11 @@ input_userauth_banner(int type, u_int32_t seq, void *ctxt) | |||
438 | debug3("input_userauth_banner"); | 470 | debug3("input_userauth_banner"); |
439 | raw = packet_get_string(&len); | 471 | raw = packet_get_string(&len); |
440 | lang = packet_get_string(NULL); | 472 | lang = packet_get_string(NULL); |
441 | if (options.log_level >= SYSLOG_LEVEL_INFO) { | 473 | if (len > 0 && options.log_level >= SYSLOG_LEVEL_INFO) { |
442 | if (len > 65536) | 474 | if (len > 65536) |
443 | len = 65536; | 475 | len = 65536; |
444 | msg = xmalloc(len * 4 + 1); /* max expansion from strnvis() */ | 476 | msg = xmalloc(len * 4 + 1); /* max expansion from strnvis() */ |
445 | strnvis(msg, raw, len * 4 + 1, VIS_SAFE|VIS_OCTAL); | 477 | strnvis(msg, raw, len * 4 + 1, VIS_SAFE|VIS_OCTAL); |
446 | msg[len*4] = '\0'; | ||
447 | fprintf(stderr, "%s", msg); | 478 | fprintf(stderr, "%s", msg); |
448 | xfree(msg); | 479 | xfree(msg); |
449 | } | 480 | } |
@@ -451,6 +482,7 @@ input_userauth_banner(int type, u_int32_t seq, void *ctxt) | |||
451 | xfree(lang); | 482 | xfree(lang); |
452 | } | 483 | } |
453 | 484 | ||
485 | /* ARGSUSED */ | ||
454 | void | 486 | void |
455 | input_userauth_success(int type, u_int32_t seq, void *ctxt) | 487 | input_userauth_success(int type, u_int32_t seq, void *ctxt) |
456 | { | 488 | { |
@@ -468,6 +500,7 @@ input_userauth_success(int type, u_int32_t seq, void *ctxt) | |||
468 | authctxt->success = 1; /* break out */ | 500 | authctxt->success = 1; /* break out */ |
469 | } | 501 | } |
470 | 502 | ||
503 | /* ARGSUSED */ | ||
471 | void | 504 | void |
472 | input_userauth_failure(int type, u_int32_t seq, void *ctxt) | 505 | input_userauth_failure(int type, u_int32_t seq, void *ctxt) |
473 | { | 506 | { |
@@ -488,6 +521,8 @@ input_userauth_failure(int type, u_int32_t seq, void *ctxt) | |||
488 | 521 | ||
489 | userauth(authctxt, authlist); | 522 | userauth(authctxt, authlist); |
490 | } | 523 | } |
524 | |||
525 | /* ARGSUSED */ | ||
491 | void | 526 | void |
492 | input_userauth_pk_ok(int type, u_int32_t seq, void *ctxt) | 527 | input_userauth_pk_ok(int type, u_int32_t seq, void *ctxt) |
493 | { | 528 | { |
@@ -567,26 +602,30 @@ userauth_gssapi(Authctxt *authctxt) | |||
567 | static u_int mech = 0; | 602 | static u_int mech = 0; |
568 | OM_uint32 min; | 603 | OM_uint32 min; |
569 | int ok = 0; | 604 | int ok = 0; |
570 | char *gss_host = NULL; | 605 | const char *gss_host; |
571 | int old_gssapi_method; | 606 | int old_gssapi_method; |
572 | 607 | ||
573 | if (options.gss_trust_dns) | 608 | if (options.gss_trust_dns) |
574 | gss_host = (char *)get_canonical_hostname(1); | 609 | gss_host = get_canonical_hostname(1); |
575 | else | 610 | else |
576 | gss_host = (char *)authctxt->host; | 611 | gss_host = authctxt->host; |
577 | 612 | ||
578 | /* Try one GSSAPI method at a time, rather than sending them all at | 613 | /* Try one GSSAPI method at a time, rather than sending them all at |
579 | * once. */ | 614 | * once. */ |
580 | 615 | ||
581 | if (gss_supported == NULL) | 616 | if (gss_supported == NULL) |
582 | gss_indicate_mechs(&min, &gss_supported); | 617 | if (GSS_ERROR(gss_indicate_mechs(&min, &gss_supported))) { |
618 | gss_supported = NULL; | ||
619 | return 0; | ||
620 | } | ||
583 | 621 | ||
584 | /* Check to see if the mechanism is usable before we offer it */ | 622 | /* Check to see if the mechanism is usable before we offer it */ |
585 | while (mech < gss_supported->count && !ok) { | 623 | while (mech < gss_supported->count && !ok) { |
586 | /* My DER encoding requires length<128 */ | 624 | /* My DER encoding requires length<128 */ |
587 | if (gss_supported->elements[mech].length < 128 && | 625 | if (gss_supported->elements[mech].length < 128 && |
588 | ssh_gssapi_check_mechanism(&gssctxt, | 626 | ssh_gssapi_check_mechanism(&gssctxt, |
589 | &gss_supported->elements[mech], gss_host)) { | 627 | &gss_supported->elements[mech], gss_host, |
628 | options.gss_client_identity)) { | ||
590 | ok = 1; /* Mechanism works */ | 629 | ok = 1; /* Mechanism works */ |
591 | } else { | 630 | } else { |
592 | mech++; | 631 | mech++; |
@@ -691,6 +730,7 @@ process_gssapi_token(void *ctxt, gss_buffer_t recv_tok) | |||
691 | return status; | 730 | return status; |
692 | } | 731 | } |
693 | 732 | ||
733 | /* ARGSUSED */ | ||
694 | void | 734 | void |
695 | input_gssapi_response(int type, u_int32_t plen, void *ctxt) | 735 | input_gssapi_response(int type, u_int32_t plen, void *ctxt) |
696 | { | 736 | { |
@@ -736,6 +776,7 @@ input_gssapi_response(int type, u_int32_t plen, void *ctxt) | |||
736 | } | 776 | } |
737 | } | 777 | } |
738 | 778 | ||
779 | /* ARGSUSED */ | ||
739 | void | 780 | void |
740 | input_gssapi_token(int type, u_int32_t plen, void *ctxt) | 781 | input_gssapi_token(int type, u_int32_t plen, void *ctxt) |
741 | { | 782 | { |
@@ -763,6 +804,7 @@ input_gssapi_token(int type, u_int32_t plen, void *ctxt) | |||
763 | } | 804 | } |
764 | } | 805 | } |
765 | 806 | ||
807 | /* ARGSUSED */ | ||
766 | void | 808 | void |
767 | input_gssapi_errtok(int type, u_int32_t plen, void *ctxt) | 809 | input_gssapi_errtok(int type, u_int32_t plen, void *ctxt) |
768 | { | 810 | { |
@@ -792,6 +834,7 @@ input_gssapi_errtok(int type, u_int32_t plen, void *ctxt) | |||
792 | /* Server will be returning a failed packet after this one */ | 834 | /* Server will be returning a failed packet after this one */ |
793 | } | 835 | } |
794 | 836 | ||
837 | /* ARGSUSED */ | ||
795 | void | 838 | void |
796 | input_gssapi_error(int type, u_int32_t plen, void *ctxt) | 839 | input_gssapi_error(int type, u_int32_t plen, void *ctxt) |
797 | { | 840 | { |
@@ -898,9 +941,11 @@ userauth_passwd(Authctxt *authctxt) | |||
898 | 941 | ||
899 | return 1; | 942 | return 1; |
900 | } | 943 | } |
944 | |||
901 | /* | 945 | /* |
902 | * parse PASSWD_CHANGEREQ, prompt user and send SSH2_MSG_USERAUTH_REQUEST | 946 | * parse PASSWD_CHANGEREQ, prompt user and send SSH2_MSG_USERAUTH_REQUEST |
903 | */ | 947 | */ |
948 | /* ARGSUSED */ | ||
904 | void | 949 | void |
905 | input_userauth_passwd_changereq(int type, u_int32_t seqnr, void *ctxt) | 950 | input_userauth_passwd_changereq(int type, u_int32_t seqnr, void *ctxt) |
906 | { | 951 | { |
@@ -965,6 +1010,209 @@ input_userauth_passwd_changereq(int type, u_int32_t seqnr, void *ctxt) | |||
965 | &input_userauth_passwd_changereq); | 1010 | &input_userauth_passwd_changereq); |
966 | } | 1011 | } |
967 | 1012 | ||
1013 | #ifdef JPAKE | ||
1014 | static char * | ||
1015 | pw_encrypt(const char *password, const char *crypt_scheme, const char *salt) | ||
1016 | { | ||
1017 | /* OpenBSD crypt(3) handles all of these */ | ||
1018 | if (strcmp(crypt_scheme, "crypt") == 0 || | ||
1019 | strcmp(crypt_scheme, "bcrypt") == 0 || | ||
1020 | strcmp(crypt_scheme, "md5crypt") == 0 || | ||
1021 | strcmp(crypt_scheme, "crypt-extended") == 0) | ||
1022 | return xstrdup(crypt(password, salt)); | ||
1023 | error("%s: unsupported password encryption scheme \"%.100s\"", | ||
1024 | __func__, crypt_scheme); | ||
1025 | return NULL; | ||
1026 | } | ||
1027 | |||
1028 | static BIGNUM * | ||
1029 | jpake_password_to_secret(Authctxt *authctxt, const char *crypt_scheme, | ||
1030 | const char *salt) | ||
1031 | { | ||
1032 | char prompt[256], *password, *crypted; | ||
1033 | u_char *secret; | ||
1034 | u_int secret_len; | ||
1035 | BIGNUM *ret; | ||
1036 | |||
1037 | snprintf(prompt, sizeof(prompt), "%.30s@%.128s's password (JPAKE): ", | ||
1038 | authctxt->server_user, authctxt->host); | ||
1039 | password = read_passphrase(prompt, 0); | ||
1040 | |||
1041 | if ((crypted = pw_encrypt(password, crypt_scheme, salt)) == NULL) { | ||
1042 | logit("Disabling %s authentication", authctxt->method->name); | ||
1043 | authctxt->method->enabled = NULL; | ||
1044 | /* Continue with an empty password to fail gracefully */ | ||
1045 | crypted = xstrdup(""); | ||
1046 | } | ||
1047 | |||
1048 | #ifdef JPAKE_DEBUG | ||
1049 | debug3("%s: salt = %s", __func__, salt); | ||
1050 | debug3("%s: scheme = %s", __func__, crypt_scheme); | ||
1051 | debug3("%s: crypted = %s", __func__, crypted); | ||
1052 | #endif | ||
1053 | |||
1054 | if (hash_buffer(crypted, strlen(crypted), EVP_sha256(), | ||
1055 | &secret, &secret_len) != 0) | ||
1056 | fatal("%s: hash_buffer", __func__); | ||
1057 | |||
1058 | bzero(password, strlen(password)); | ||
1059 | bzero(crypted, strlen(crypted)); | ||
1060 | xfree(password); | ||
1061 | xfree(crypted); | ||
1062 | |||
1063 | if ((ret = BN_bin2bn(secret, secret_len, NULL)) == NULL) | ||
1064 | fatal("%s: BN_bin2bn (secret)", __func__); | ||
1065 | bzero(secret, secret_len); | ||
1066 | xfree(secret); | ||
1067 | |||
1068 | return ret; | ||
1069 | } | ||
1070 | |||
1071 | /* ARGSUSED */ | ||
1072 | void | ||
1073 | input_userauth_jpake_server_step1(int type, u_int32_t seq, void *ctxt) | ||
1074 | { | ||
1075 | Authctxt *authctxt = ctxt; | ||
1076 | struct jpake_ctx *pctx = authctxt->methoddata; | ||
1077 | u_char *x3_proof, *x4_proof, *x2_s_proof; | ||
1078 | u_int x3_proof_len, x4_proof_len, x2_s_proof_len; | ||
1079 | char *crypt_scheme, *salt; | ||
1080 | |||
1081 | /* Disable this message */ | ||
1082 | dispatch_set(SSH2_MSG_USERAUTH_JPAKE_SERVER_STEP1, NULL); | ||
1083 | |||
1084 | if ((pctx->g_x3 = BN_new()) == NULL || | ||
1085 | (pctx->g_x4 = BN_new()) == NULL) | ||
1086 | fatal("%s: BN_new", __func__); | ||
1087 | |||
1088 | /* Fetch step 1 values */ | ||
1089 | crypt_scheme = packet_get_string(NULL); | ||
1090 | salt = packet_get_string(NULL); | ||
1091 | pctx->server_id = packet_get_string(&pctx->server_id_len); | ||
1092 | packet_get_bignum2(pctx->g_x3); | ||
1093 | packet_get_bignum2(pctx->g_x4); | ||
1094 | x3_proof = packet_get_string(&x3_proof_len); | ||
1095 | x4_proof = packet_get_string(&x4_proof_len); | ||
1096 | packet_check_eom(); | ||
1097 | |||
1098 | JPAKE_DEBUG_CTX((pctx, "step 1 received in %s", __func__)); | ||
1099 | |||
1100 | /* Obtain password and derive secret */ | ||
1101 | pctx->s = jpake_password_to_secret(authctxt, crypt_scheme, salt); | ||
1102 | bzero(crypt_scheme, strlen(crypt_scheme)); | ||
1103 | bzero(salt, strlen(salt)); | ||
1104 | xfree(crypt_scheme); | ||
1105 | xfree(salt); | ||
1106 | JPAKE_DEBUG_BN((pctx->s, "%s: s = ", __func__)); | ||
1107 | |||
1108 | /* Calculate step 2 values */ | ||
1109 | jpake_step2(pctx->grp, pctx->s, pctx->g_x1, | ||
1110 | pctx->g_x3, pctx->g_x4, pctx->x2, | ||
1111 | pctx->server_id, pctx->server_id_len, | ||
1112 | pctx->client_id, pctx->client_id_len, | ||
1113 | x3_proof, x3_proof_len, | ||
1114 | x4_proof, x4_proof_len, | ||
1115 | &pctx->a, | ||
1116 | &x2_s_proof, &x2_s_proof_len); | ||
1117 | |||
1118 | bzero(x3_proof, x3_proof_len); | ||
1119 | bzero(x4_proof, x4_proof_len); | ||
1120 | xfree(x3_proof); | ||
1121 | xfree(x4_proof); | ||
1122 | |||
1123 | JPAKE_DEBUG_CTX((pctx, "step 2 sending in %s", __func__)); | ||
1124 | |||
1125 | /* Send values for step 2 */ | ||
1126 | packet_start(SSH2_MSG_USERAUTH_JPAKE_CLIENT_STEP2); | ||
1127 | packet_put_bignum2(pctx->a); | ||
1128 | packet_put_string(x2_s_proof, x2_s_proof_len); | ||
1129 | packet_send(); | ||
1130 | |||
1131 | bzero(x2_s_proof, x2_s_proof_len); | ||
1132 | xfree(x2_s_proof); | ||
1133 | |||
1134 | /* Expect step 2 packet from peer */ | ||
1135 | dispatch_set(SSH2_MSG_USERAUTH_JPAKE_SERVER_STEP2, | ||
1136 | input_userauth_jpake_server_step2); | ||
1137 | } | ||
1138 | |||
1139 | /* ARGSUSED */ | ||
1140 | void | ||
1141 | input_userauth_jpake_server_step2(int type, u_int32_t seq, void *ctxt) | ||
1142 | { | ||
1143 | Authctxt *authctxt = ctxt; | ||
1144 | struct jpake_ctx *pctx = authctxt->methoddata; | ||
1145 | u_char *x4_s_proof; | ||
1146 | u_int x4_s_proof_len; | ||
1147 | |||
1148 | /* Disable this message */ | ||
1149 | dispatch_set(SSH2_MSG_USERAUTH_JPAKE_SERVER_STEP2, NULL); | ||
1150 | |||
1151 | if ((pctx->b = BN_new()) == NULL) | ||
1152 | fatal("%s: BN_new", __func__); | ||
1153 | |||
1154 | /* Fetch step 2 values */ | ||
1155 | packet_get_bignum2(pctx->b); | ||
1156 | x4_s_proof = packet_get_string(&x4_s_proof_len); | ||
1157 | packet_check_eom(); | ||
1158 | |||
1159 | JPAKE_DEBUG_CTX((pctx, "step 2 received in %s", __func__)); | ||
1160 | |||
1161 | /* Derive shared key and calculate confirmation hash */ | ||
1162 | jpake_key_confirm(pctx->grp, pctx->s, pctx->b, | ||
1163 | pctx->x2, pctx->g_x1, pctx->g_x2, pctx->g_x3, pctx->g_x4, | ||
1164 | pctx->client_id, pctx->client_id_len, | ||
1165 | pctx->server_id, pctx->server_id_len, | ||
1166 | session_id2, session_id2_len, | ||
1167 | x4_s_proof, x4_s_proof_len, | ||
1168 | &pctx->k, | ||
1169 | &pctx->h_k_cid_sessid, &pctx->h_k_cid_sessid_len); | ||
1170 | |||
1171 | bzero(x4_s_proof, x4_s_proof_len); | ||
1172 | xfree(x4_s_proof); | ||
1173 | |||
1174 | JPAKE_DEBUG_CTX((pctx, "confirm sending in %s", __func__)); | ||
1175 | |||
1176 | /* Send key confirmation proof */ | ||
1177 | packet_start(SSH2_MSG_USERAUTH_JPAKE_CLIENT_CONFIRM); | ||
1178 | packet_put_string(pctx->h_k_cid_sessid, pctx->h_k_cid_sessid_len); | ||
1179 | packet_send(); | ||
1180 | |||
1181 | /* Expect confirmation from peer */ | ||
1182 | dispatch_set(SSH2_MSG_USERAUTH_JPAKE_SERVER_CONFIRM, | ||
1183 | input_userauth_jpake_server_confirm); | ||
1184 | } | ||
1185 | |||
1186 | /* ARGSUSED */ | ||
1187 | void | ||
1188 | input_userauth_jpake_server_confirm(int type, u_int32_t seq, void *ctxt) | ||
1189 | { | ||
1190 | Authctxt *authctxt = ctxt; | ||
1191 | struct jpake_ctx *pctx = authctxt->methoddata; | ||
1192 | |||
1193 | /* Disable this message */ | ||
1194 | dispatch_set(SSH2_MSG_USERAUTH_JPAKE_SERVER_CONFIRM, NULL); | ||
1195 | |||
1196 | pctx->h_k_sid_sessid = packet_get_string(&pctx->h_k_sid_sessid_len); | ||
1197 | packet_check_eom(); | ||
1198 | |||
1199 | JPAKE_DEBUG_CTX((pctx, "confirm received in %s", __func__)); | ||
1200 | |||
1201 | /* Verify expected confirmation hash */ | ||
1202 | if (jpake_check_confirm(pctx->k, | ||
1203 | pctx->server_id, pctx->server_id_len, | ||
1204 | session_id2, session_id2_len, | ||
1205 | pctx->h_k_sid_sessid, pctx->h_k_sid_sessid_len) == 1) | ||
1206 | debug("%s: %s success", __func__, authctxt->method->name); | ||
1207 | else { | ||
1208 | debug("%s: confirmation mismatch", __func__); | ||
1209 | /* XXX stash this so if auth succeeds then we can warn/kill */ | ||
1210 | } | ||
1211 | |||
1212 | userauth_jpake_cleanup(authctxt); | ||
1213 | } | ||
1214 | #endif /* JPAKE */ | ||
1215 | |||
968 | static int | 1216 | static int |
969 | identity_sign(Identity *id, u_char **sigp, u_int *lenp, | 1217 | identity_sign(Identity *id, u_char **sigp, u_int *lenp, |
970 | u_char *data, u_int datalen) | 1218 | u_char *data, u_int datalen) |
@@ -1541,6 +1789,76 @@ userauth_hostbased(Authctxt *authctxt) | |||
1541 | return 1; | 1789 | return 1; |
1542 | } | 1790 | } |
1543 | 1791 | ||
1792 | #ifdef JPAKE | ||
1793 | int | ||
1794 | userauth_jpake(Authctxt *authctxt) | ||
1795 | { | ||
1796 | struct jpake_ctx *pctx; | ||
1797 | u_char *x1_proof, *x2_proof; | ||
1798 | u_int x1_proof_len, x2_proof_len; | ||
1799 | static int attempt = 0; /* XXX share with userauth_password's? */ | ||
1800 | |||
1801 | if (attempt++ >= options.number_of_password_prompts) | ||
1802 | return 0; | ||
1803 | if (attempt != 1) | ||
1804 | error("Permission denied, please try again."); | ||
1805 | |||
1806 | if (authctxt->methoddata != NULL) | ||
1807 | fatal("%s: authctxt->methoddata already set (%p)", | ||
1808 | __func__, authctxt->methoddata); | ||
1809 | |||
1810 | authctxt->methoddata = pctx = jpake_new(); | ||
1811 | |||
1812 | /* | ||
1813 | * Send request immediately, to get the protocol going while | ||
1814 | * we do the initial computations. | ||
1815 | */ | ||
1816 | packet_start(SSH2_MSG_USERAUTH_REQUEST); | ||
1817 | packet_put_cstring(authctxt->server_user); | ||
1818 | packet_put_cstring(authctxt->service); | ||
1819 | packet_put_cstring(authctxt->method->name); | ||
1820 | packet_send(); | ||
1821 | packet_write_wait(); | ||
1822 | |||
1823 | jpake_step1(pctx->grp, | ||
1824 | &pctx->client_id, &pctx->client_id_len, | ||
1825 | &pctx->x1, &pctx->x2, &pctx->g_x1, &pctx->g_x2, | ||
1826 | &x1_proof, &x1_proof_len, | ||
1827 | &x2_proof, &x2_proof_len); | ||
1828 | |||
1829 | JPAKE_DEBUG_CTX((pctx, "step 1 sending in %s", __func__)); | ||
1830 | |||
1831 | packet_start(SSH2_MSG_USERAUTH_JPAKE_CLIENT_STEP1); | ||
1832 | packet_put_string(pctx->client_id, pctx->client_id_len); | ||
1833 | packet_put_bignum2(pctx->g_x1); | ||
1834 | packet_put_bignum2(pctx->g_x2); | ||
1835 | packet_put_string(x1_proof, x1_proof_len); | ||
1836 | packet_put_string(x2_proof, x2_proof_len); | ||
1837 | packet_send(); | ||
1838 | |||
1839 | bzero(x1_proof, x1_proof_len); | ||
1840 | bzero(x2_proof, x2_proof_len); | ||
1841 | xfree(x1_proof); | ||
1842 | xfree(x2_proof); | ||
1843 | |||
1844 | /* Expect step 1 packet from peer */ | ||
1845 | dispatch_set(SSH2_MSG_USERAUTH_JPAKE_SERVER_STEP1, | ||
1846 | input_userauth_jpake_server_step1); | ||
1847 | |||
1848 | return 1; | ||
1849 | } | ||
1850 | |||
1851 | void | ||
1852 | userauth_jpake_cleanup(Authctxt *authctxt) | ||
1853 | { | ||
1854 | debug3("%s: clean up", __func__); | ||
1855 | if (authctxt->methoddata != NULL) { | ||
1856 | jpake_free(authctxt->methoddata); | ||
1857 | authctxt->methoddata = NULL; | ||
1858 | } | ||
1859 | } | ||
1860 | #endif /* JPAKE */ | ||
1861 | |||
1544 | /* find auth method */ | 1862 | /* find auth method */ |
1545 | 1863 | ||
1546 | /* | 1864 | /* |
@@ -1642,3 +1960,4 @@ authmethods_get(void) | |||
1642 | buffer_free(&b); | 1960 | buffer_free(&b); |
1643 | return list; | 1961 | return list; |
1644 | } | 1962 | } |
1963 | |||