diff options
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 | |||