diff options
Diffstat (limited to 'sshconnect2.c')
-rw-r--r-- | sshconnect2.c | 356 |
1 files changed, 338 insertions, 18 deletions
diff --git a/sshconnect2.c b/sshconnect2.c index f7d34bf02..a96153903 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,30 +309,43 @@ 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 | #endif | 315 | #endif |
301 | {"hostbased", | 316 | {"hostbased", |
302 | userauth_hostbased, | 317 | userauth_hostbased, |
318 | NULL, | ||
303 | &options.hostbased_authentication, | 319 | &options.hostbased_authentication, |
304 | NULL}, | 320 | NULL}, |
305 | {"publickey", | 321 | {"publickey", |
306 | userauth_pubkey, | 322 | userauth_pubkey, |
323 | NULL, | ||
307 | &options.pubkey_authentication, | 324 | &options.pubkey_authentication, |
308 | NULL}, | 325 | NULL}, |
326 | #ifdef JPAKE | ||
327 | {"jpake-01@openssh.com", | ||
328 | userauth_jpake, | ||
329 | userauth_jpake_cleanup, | ||
330 | &options.zero_knowledge_password_authentication, | ||
331 | &options.batch_mode}, | ||
332 | #endif | ||
309 | {"keyboard-interactive", | 333 | {"keyboard-interactive", |
310 | userauth_kbdint, | 334 | userauth_kbdint, |
335 | NULL, | ||
311 | &options.kbd_interactive_authentication, | 336 | &options.kbd_interactive_authentication, |
312 | &options.batch_mode}, | 337 | &options.batch_mode}, |
313 | {"password", | 338 | {"password", |
314 | userauth_passwd, | 339 | userauth_passwd, |
340 | NULL, | ||
315 | &options.password_authentication, | 341 | &options.password_authentication, |
316 | &options.batch_mode}, | 342 | &options.batch_mode}, |
317 | {"none", | 343 | {"none", |
318 | userauth_none, | 344 | userauth_none, |
319 | NULL, | 345 | NULL, |
346 | NULL, | ||
320 | NULL}, | 347 | NULL}, |
321 | {NULL, NULL, NULL, NULL} | 348 | {NULL, NULL, NULL, NULL, NULL} |
322 | }; | 349 | }; |
323 | 350 | ||
324 | void | 351 | void |
@@ -386,6 +413,9 @@ ssh_userauth2(const char *local_user, const char *server_user, char *host, | |||
386 | void | 413 | void |
387 | userauth(Authctxt *authctxt, char *authlist) | 414 | userauth(Authctxt *authctxt, char *authlist) |
388 | { | 415 | { |
416 | if (authctxt->method != NULL && authctxt->method->cleanup != NULL) | ||
417 | authctxt->method->cleanup(authctxt); | ||
418 | |||
389 | if (authctxt->methoddata) { | 419 | if (authctxt->methoddata) { |
390 | xfree(authctxt->methoddata); | 420 | xfree(authctxt->methoddata); |
391 | authctxt->methoddata = NULL; | 421 | authctxt->methoddata = NULL; |
@@ -418,6 +448,7 @@ userauth(Authctxt *authctxt, char *authlist) | |||
418 | } | 448 | } |
419 | } | 449 | } |
420 | 450 | ||
451 | /* ARGSUSED */ | ||
421 | void | 452 | void |
422 | input_userauth_error(int type, u_int32_t seq, void *ctxt) | 453 | input_userauth_error(int type, u_int32_t seq, void *ctxt) |
423 | { | 454 | { |
@@ -425,6 +456,7 @@ input_userauth_error(int type, u_int32_t seq, void *ctxt) | |||
425 | "type %d", type); | 456 | "type %d", type); |
426 | } | 457 | } |
427 | 458 | ||
459 | /* ARGSUSED */ | ||
428 | void | 460 | void |
429 | input_userauth_banner(int type, u_int32_t seq, void *ctxt) | 461 | input_userauth_banner(int type, u_int32_t seq, void *ctxt) |
430 | { | 462 | { |
@@ -434,11 +466,11 @@ input_userauth_banner(int type, u_int32_t seq, void *ctxt) | |||
434 | debug3("input_userauth_banner"); | 466 | debug3("input_userauth_banner"); |
435 | raw = packet_get_string(&len); | 467 | raw = packet_get_string(&len); |
436 | lang = packet_get_string(NULL); | 468 | lang = packet_get_string(NULL); |
437 | if (options.log_level >= SYSLOG_LEVEL_INFO) { | 469 | if (len > 0 && options.log_level >= SYSLOG_LEVEL_INFO) { |
438 | if (len > 65536) | 470 | if (len > 65536) |
439 | len = 65536; | 471 | len = 65536; |
440 | msg = xmalloc(len * 4); /* max expansion from strnvis() */ | 472 | msg = xmalloc(len * 4 + 1); /* max expansion from strnvis() */ |
441 | strnvis(msg, raw, len * 4, VIS_SAFE|VIS_OCTAL); | 473 | strnvis(msg, raw, len * 4 + 1, VIS_SAFE|VIS_OCTAL); |
442 | fprintf(stderr, "%s", msg); | 474 | fprintf(stderr, "%s", msg); |
443 | xfree(msg); | 475 | xfree(msg); |
444 | } | 476 | } |
@@ -446,6 +478,7 @@ input_userauth_banner(int type, u_int32_t seq, void *ctxt) | |||
446 | xfree(lang); | 478 | xfree(lang); |
447 | } | 479 | } |
448 | 480 | ||
481 | /* ARGSUSED */ | ||
449 | void | 482 | void |
450 | input_userauth_success(int type, u_int32_t seq, void *ctxt) | 483 | input_userauth_success(int type, u_int32_t seq, void *ctxt) |
451 | { | 484 | { |
@@ -463,6 +496,7 @@ input_userauth_success(int type, u_int32_t seq, void *ctxt) | |||
463 | authctxt->success = 1; /* break out */ | 496 | authctxt->success = 1; /* break out */ |
464 | } | 497 | } |
465 | 498 | ||
499 | /* ARGSUSED */ | ||
466 | void | 500 | void |
467 | input_userauth_failure(int type, u_int32_t seq, void *ctxt) | 501 | input_userauth_failure(int type, u_int32_t seq, void *ctxt) |
468 | { | 502 | { |
@@ -483,6 +517,8 @@ input_userauth_failure(int type, u_int32_t seq, void *ctxt) | |||
483 | 517 | ||
484 | userauth(authctxt, authlist); | 518 | userauth(authctxt, authlist); |
485 | } | 519 | } |
520 | |||
521 | /* ARGSUSED */ | ||
486 | void | 522 | void |
487 | input_userauth_pk_ok(int type, u_int32_t seq, void *ctxt) | 523 | input_userauth_pk_ok(int type, u_int32_t seq, void *ctxt) |
488 | { | 524 | { |
@@ -562,25 +598,29 @@ userauth_gssapi(Authctxt *authctxt) | |||
562 | static u_int mech = 0; | 598 | static u_int mech = 0; |
563 | OM_uint32 min; | 599 | OM_uint32 min; |
564 | int ok = 0; | 600 | int ok = 0; |
565 | char *gss_host = NULL; | 601 | const char *gss_host; |
566 | 602 | ||
567 | if (options.gss_trust_dns) | 603 | if (options.gss_trust_dns) |
568 | gss_host = (char *)get_canonical_hostname(1); | 604 | gss_host = get_canonical_hostname(1); |
569 | else | 605 | else |
570 | gss_host = (char *)authctxt->host; | 606 | gss_host = authctxt->host; |
571 | 607 | ||
572 | /* Try one GSSAPI method at a time, rather than sending them all at | 608 | /* Try one GSSAPI method at a time, rather than sending them all at |
573 | * once. */ | 609 | * once. */ |
574 | 610 | ||
575 | if (gss_supported == NULL) | 611 | if (gss_supported == NULL) |
576 | gss_indicate_mechs(&min, &gss_supported); | 612 | if (GSS_ERROR(gss_indicate_mechs(&min, &gss_supported))) { |
613 | gss_supported = NULL; | ||
614 | return 0; | ||
615 | } | ||
577 | 616 | ||
578 | /* Check to see if the mechanism is usable before we offer it */ | 617 | /* Check to see if the mechanism is usable before we offer it */ |
579 | while (mech < gss_supported->count && !ok) { | 618 | while (mech < gss_supported->count && !ok) { |
580 | /* My DER encoding requires length<128 */ | 619 | /* My DER encoding requires length<128 */ |
581 | if (gss_supported->elements[mech].length < 128 && | 620 | if (gss_supported->elements[mech].length < 128 && |
582 | ssh_gssapi_check_mechanism(&gssctxt, | 621 | ssh_gssapi_check_mechanism(&gssctxt, |
583 | &gss_supported->elements[mech], gss_host)) { | 622 | &gss_supported->elements[mech], gss_host, |
623 | options.gss_client_identity)) { | ||
584 | ok = 1; /* Mechanism works */ | 624 | ok = 1; /* Mechanism works */ |
585 | } else { | 625 | } else { |
586 | mech++; | 626 | mech++; |
@@ -671,6 +711,7 @@ process_gssapi_token(void *ctxt, gss_buffer_t recv_tok) | |||
671 | return status; | 711 | return status; |
672 | } | 712 | } |
673 | 713 | ||
714 | /* ARGSUSED */ | ||
674 | void | 715 | void |
675 | input_gssapi_response(int type, u_int32_t plen, void *ctxt) | 716 | input_gssapi_response(int type, u_int32_t plen, void *ctxt) |
676 | { | 717 | { |
@@ -710,6 +751,7 @@ input_gssapi_response(int type, u_int32_t plen, void *ctxt) | |||
710 | } | 751 | } |
711 | } | 752 | } |
712 | 753 | ||
754 | /* ARGSUSED */ | ||
713 | void | 755 | void |
714 | input_gssapi_token(int type, u_int32_t plen, void *ctxt) | 756 | input_gssapi_token(int type, u_int32_t plen, void *ctxt) |
715 | { | 757 | { |
@@ -737,6 +779,7 @@ input_gssapi_token(int type, u_int32_t plen, void *ctxt) | |||
737 | } | 779 | } |
738 | } | 780 | } |
739 | 781 | ||
782 | /* ARGSUSED */ | ||
740 | void | 783 | void |
741 | input_gssapi_errtok(int type, u_int32_t plen, void *ctxt) | 784 | input_gssapi_errtok(int type, u_int32_t plen, void *ctxt) |
742 | { | 785 | { |
@@ -766,6 +809,7 @@ input_gssapi_errtok(int type, u_int32_t plen, void *ctxt) | |||
766 | /* Server will be returning a failed packet after this one */ | 809 | /* Server will be returning a failed packet after this one */ |
767 | } | 810 | } |
768 | 811 | ||
812 | /* ARGSUSED */ | ||
769 | void | 813 | void |
770 | input_gssapi_error(int type, u_int32_t plen, void *ctxt) | 814 | input_gssapi_error(int type, u_int32_t plen, void *ctxt) |
771 | { | 815 | { |
@@ -872,9 +916,11 @@ userauth_passwd(Authctxt *authctxt) | |||
872 | 916 | ||
873 | return 1; | 917 | return 1; |
874 | } | 918 | } |
919 | |||
875 | /* | 920 | /* |
876 | * parse PASSWD_CHANGEREQ, prompt user and send SSH2_MSG_USERAUTH_REQUEST | 921 | * parse PASSWD_CHANGEREQ, prompt user and send SSH2_MSG_USERAUTH_REQUEST |
877 | */ | 922 | */ |
923 | /* ARGSUSED */ | ||
878 | void | 924 | void |
879 | input_userauth_passwd_changereq(int type, u_int32_t seqnr, void *ctxt) | 925 | input_userauth_passwd_changereq(int type, u_int32_t seqnr, void *ctxt) |
880 | { | 926 | { |
@@ -939,6 +985,209 @@ input_userauth_passwd_changereq(int type, u_int32_t seqnr, void *ctxt) | |||
939 | &input_userauth_passwd_changereq); | 985 | &input_userauth_passwd_changereq); |
940 | } | 986 | } |
941 | 987 | ||
988 | #ifdef JPAKE | ||
989 | static char * | ||
990 | pw_encrypt(const char *password, const char *crypt_scheme, const char *salt) | ||
991 | { | ||
992 | /* OpenBSD crypt(3) handles all of these */ | ||
993 | if (strcmp(crypt_scheme, "crypt") == 0 || | ||
994 | strcmp(crypt_scheme, "bcrypt") == 0 || | ||
995 | strcmp(crypt_scheme, "md5crypt") == 0 || | ||
996 | strcmp(crypt_scheme, "crypt-extended") == 0) | ||
997 | return xstrdup(crypt(password, salt)); | ||
998 | error("%s: unsupported password encryption scheme \"%.100s\"", | ||
999 | __func__, crypt_scheme); | ||
1000 | return NULL; | ||
1001 | } | ||
1002 | |||
1003 | static BIGNUM * | ||
1004 | jpake_password_to_secret(Authctxt *authctxt, const char *crypt_scheme, | ||
1005 | const char *salt) | ||
1006 | { | ||
1007 | char prompt[256], *password, *crypted; | ||
1008 | u_char *secret; | ||
1009 | u_int secret_len; | ||
1010 | BIGNUM *ret; | ||
1011 | |||
1012 | snprintf(prompt, sizeof(prompt), "%.30s@%.128s's password (JPAKE): ", | ||
1013 | authctxt->server_user, authctxt->host); | ||
1014 | password = read_passphrase(prompt, 0); | ||
1015 | |||
1016 | if ((crypted = pw_encrypt(password, crypt_scheme, salt)) == NULL) { | ||
1017 | logit("Disabling %s authentication", authctxt->method->name); | ||
1018 | authctxt->method->enabled = NULL; | ||
1019 | /* Continue with an empty password to fail gracefully */ | ||
1020 | crypted = xstrdup(""); | ||
1021 | } | ||
1022 | |||
1023 | #ifdef JPAKE_DEBUG | ||
1024 | debug3("%s: salt = %s", __func__, salt); | ||
1025 | debug3("%s: scheme = %s", __func__, crypt_scheme); | ||
1026 | debug3("%s: crypted = %s", __func__, crypted); | ||
1027 | #endif | ||
1028 | |||
1029 | if (hash_buffer(crypted, strlen(crypted), EVP_sha256(), | ||
1030 | &secret, &secret_len) != 0) | ||
1031 | fatal("%s: hash_buffer", __func__); | ||
1032 | |||
1033 | bzero(password, strlen(password)); | ||
1034 | bzero(crypted, strlen(crypted)); | ||
1035 | xfree(password); | ||
1036 | xfree(crypted); | ||
1037 | |||
1038 | if ((ret = BN_bin2bn(secret, secret_len, NULL)) == NULL) | ||
1039 | fatal("%s: BN_bin2bn (secret)", __func__); | ||
1040 | bzero(secret, secret_len); | ||
1041 | xfree(secret); | ||
1042 | |||
1043 | return ret; | ||
1044 | } | ||
1045 | |||
1046 | /* ARGSUSED */ | ||
1047 | void | ||
1048 | input_userauth_jpake_server_step1(int type, u_int32_t seq, void *ctxt) | ||
1049 | { | ||
1050 | Authctxt *authctxt = ctxt; | ||
1051 | struct jpake_ctx *pctx = authctxt->methoddata; | ||
1052 | u_char *x3_proof, *x4_proof, *x2_s_proof; | ||
1053 | u_int x3_proof_len, x4_proof_len, x2_s_proof_len; | ||
1054 | char *crypt_scheme, *salt; | ||
1055 | |||
1056 | /* Disable this message */ | ||
1057 | dispatch_set(SSH2_MSG_USERAUTH_JPAKE_SERVER_STEP1, NULL); | ||
1058 | |||
1059 | if ((pctx->g_x3 = BN_new()) == NULL || | ||
1060 | (pctx->g_x4 = BN_new()) == NULL) | ||
1061 | fatal("%s: BN_new", __func__); | ||
1062 | |||
1063 | /* Fetch step 1 values */ | ||
1064 | crypt_scheme = packet_get_string(NULL); | ||
1065 | salt = packet_get_string(NULL); | ||
1066 | pctx->server_id = packet_get_string(&pctx->server_id_len); | ||
1067 | packet_get_bignum2(pctx->g_x3); | ||
1068 | packet_get_bignum2(pctx->g_x4); | ||
1069 | x3_proof = packet_get_string(&x3_proof_len); | ||
1070 | x4_proof = packet_get_string(&x4_proof_len); | ||
1071 | packet_check_eom(); | ||
1072 | |||
1073 | JPAKE_DEBUG_CTX((pctx, "step 1 received in %s", __func__)); | ||
1074 | |||
1075 | /* Obtain password and derive secret */ | ||
1076 | pctx->s = jpake_password_to_secret(authctxt, crypt_scheme, salt); | ||
1077 | bzero(crypt_scheme, strlen(crypt_scheme)); | ||
1078 | bzero(salt, strlen(salt)); | ||
1079 | xfree(crypt_scheme); | ||
1080 | xfree(salt); | ||
1081 | JPAKE_DEBUG_BN((pctx->s, "%s: s = ", __func__)); | ||
1082 | |||
1083 | /* Calculate step 2 values */ | ||
1084 | jpake_step2(pctx->grp, pctx->s, pctx->g_x1, | ||
1085 | pctx->g_x3, pctx->g_x4, pctx->x2, | ||
1086 | pctx->server_id, pctx->server_id_len, | ||
1087 | pctx->client_id, pctx->client_id_len, | ||
1088 | x3_proof, x3_proof_len, | ||
1089 | x4_proof, x4_proof_len, | ||
1090 | &pctx->a, | ||
1091 | &x2_s_proof, &x2_s_proof_len); | ||
1092 | |||
1093 | bzero(x3_proof, x3_proof_len); | ||
1094 | bzero(x4_proof, x4_proof_len); | ||
1095 | xfree(x3_proof); | ||
1096 | xfree(x4_proof); | ||
1097 | |||
1098 | JPAKE_DEBUG_CTX((pctx, "step 2 sending in %s", __func__)); | ||
1099 | |||
1100 | /* Send values for step 2 */ | ||
1101 | packet_start(SSH2_MSG_USERAUTH_JPAKE_CLIENT_STEP2); | ||
1102 | packet_put_bignum2(pctx->a); | ||
1103 | packet_put_string(x2_s_proof, x2_s_proof_len); | ||
1104 | packet_send(); | ||
1105 | |||
1106 | bzero(x2_s_proof, x2_s_proof_len); | ||
1107 | xfree(x2_s_proof); | ||
1108 | |||
1109 | /* Expect step 2 packet from peer */ | ||
1110 | dispatch_set(SSH2_MSG_USERAUTH_JPAKE_SERVER_STEP2, | ||
1111 | input_userauth_jpake_server_step2); | ||
1112 | } | ||
1113 | |||
1114 | /* ARGSUSED */ | ||
1115 | void | ||
1116 | input_userauth_jpake_server_step2(int type, u_int32_t seq, void *ctxt) | ||
1117 | { | ||
1118 | Authctxt *authctxt = ctxt; | ||
1119 | struct jpake_ctx *pctx = authctxt->methoddata; | ||
1120 | u_char *x4_s_proof; | ||
1121 | u_int x4_s_proof_len; | ||
1122 | |||
1123 | /* Disable this message */ | ||
1124 | dispatch_set(SSH2_MSG_USERAUTH_JPAKE_SERVER_STEP2, NULL); | ||
1125 | |||
1126 | if ((pctx->b = BN_new()) == NULL) | ||
1127 | fatal("%s: BN_new", __func__); | ||
1128 | |||
1129 | /* Fetch step 2 values */ | ||
1130 | packet_get_bignum2(pctx->b); | ||
1131 | x4_s_proof = packet_get_string(&x4_s_proof_len); | ||
1132 | packet_check_eom(); | ||
1133 | |||
1134 | JPAKE_DEBUG_CTX((pctx, "step 2 received in %s", __func__)); | ||
1135 | |||
1136 | /* Derive shared key and calculate confirmation hash */ | ||
1137 | jpake_key_confirm(pctx->grp, pctx->s, pctx->b, | ||
1138 | pctx->x2, pctx->g_x1, pctx->g_x2, pctx->g_x3, pctx->g_x4, | ||
1139 | pctx->client_id, pctx->client_id_len, | ||
1140 | pctx->server_id, pctx->server_id_len, | ||
1141 | session_id2, session_id2_len, | ||
1142 | x4_s_proof, x4_s_proof_len, | ||
1143 | &pctx->k, | ||
1144 | &pctx->h_k_cid_sessid, &pctx->h_k_cid_sessid_len); | ||
1145 | |||
1146 | bzero(x4_s_proof, x4_s_proof_len); | ||
1147 | xfree(x4_s_proof); | ||
1148 | |||
1149 | JPAKE_DEBUG_CTX((pctx, "confirm sending in %s", __func__)); | ||
1150 | |||
1151 | /* Send key confirmation proof */ | ||
1152 | packet_start(SSH2_MSG_USERAUTH_JPAKE_CLIENT_CONFIRM); | ||
1153 | packet_put_string(pctx->h_k_cid_sessid, pctx->h_k_cid_sessid_len); | ||
1154 | packet_send(); | ||
1155 | |||
1156 | /* Expect confirmation from peer */ | ||
1157 | dispatch_set(SSH2_MSG_USERAUTH_JPAKE_SERVER_CONFIRM, | ||
1158 | input_userauth_jpake_server_confirm); | ||
1159 | } | ||
1160 | |||
1161 | /* ARGSUSED */ | ||
1162 | void | ||
1163 | input_userauth_jpake_server_confirm(int type, u_int32_t seq, void *ctxt) | ||
1164 | { | ||
1165 | Authctxt *authctxt = ctxt; | ||
1166 | struct jpake_ctx *pctx = authctxt->methoddata; | ||
1167 | |||
1168 | /* Disable this message */ | ||
1169 | dispatch_set(SSH2_MSG_USERAUTH_JPAKE_SERVER_CONFIRM, NULL); | ||
1170 | |||
1171 | pctx->h_k_sid_sessid = packet_get_string(&pctx->h_k_sid_sessid_len); | ||
1172 | packet_check_eom(); | ||
1173 | |||
1174 | JPAKE_DEBUG_CTX((pctx, "confirm received in %s", __func__)); | ||
1175 | |||
1176 | /* Verify expected confirmation hash */ | ||
1177 | if (jpake_check_confirm(pctx->k, | ||
1178 | pctx->server_id, pctx->server_id_len, | ||
1179 | session_id2, session_id2_len, | ||
1180 | pctx->h_k_sid_sessid, pctx->h_k_sid_sessid_len) == 1) | ||
1181 | debug("%s: %s success", __func__, authctxt->method->name); | ||
1182 | else { | ||
1183 | debug("%s: confirmation mismatch", __func__); | ||
1184 | /* XXX stash this so if auth succeeds then we can warn/kill */ | ||
1185 | } | ||
1186 | |||
1187 | userauth_jpake_cleanup(authctxt); | ||
1188 | } | ||
1189 | #endif /* JPAKE */ | ||
1190 | |||
942 | static int | 1191 | static int |
943 | identity_sign(Identity *id, u_char **sigp, u_int *lenp, | 1192 | identity_sign(Identity *id, u_char **sigp, u_int *lenp, |
944 | u_char *data, u_int datalen) | 1193 | u_char *data, u_int datalen) |
@@ -1513,6 +1762,76 @@ userauth_hostbased(Authctxt *authctxt) | |||
1513 | return 1; | 1762 | return 1; |
1514 | } | 1763 | } |
1515 | 1764 | ||
1765 | #ifdef JPAKE | ||
1766 | int | ||
1767 | userauth_jpake(Authctxt *authctxt) | ||
1768 | { | ||
1769 | struct jpake_ctx *pctx; | ||
1770 | u_char *x1_proof, *x2_proof; | ||
1771 | u_int x1_proof_len, x2_proof_len; | ||
1772 | static int attempt = 0; /* XXX share with userauth_password's? */ | ||
1773 | |||
1774 | if (attempt++ >= options.number_of_password_prompts) | ||
1775 | return 0; | ||
1776 | if (attempt != 1) | ||
1777 | error("Permission denied, please try again."); | ||
1778 | |||
1779 | if (authctxt->methoddata != NULL) | ||
1780 | fatal("%s: authctxt->methoddata already set (%p)", | ||
1781 | __func__, authctxt->methoddata); | ||
1782 | |||
1783 | authctxt->methoddata = pctx = jpake_new(); | ||
1784 | |||
1785 | /* | ||
1786 | * Send request immediately, to get the protocol going while | ||
1787 | * we do the initial computations. | ||
1788 | */ | ||
1789 | packet_start(SSH2_MSG_USERAUTH_REQUEST); | ||
1790 | packet_put_cstring(authctxt->server_user); | ||
1791 | packet_put_cstring(authctxt->service); | ||
1792 | packet_put_cstring(authctxt->method->name); | ||
1793 | packet_send(); | ||
1794 | packet_write_wait(); | ||
1795 | |||
1796 | jpake_step1(pctx->grp, | ||
1797 | &pctx->client_id, &pctx->client_id_len, | ||
1798 | &pctx->x1, &pctx->x2, &pctx->g_x1, &pctx->g_x2, | ||
1799 | &x1_proof, &x1_proof_len, | ||
1800 | &x2_proof, &x2_proof_len); | ||
1801 | |||
1802 | JPAKE_DEBUG_CTX((pctx, "step 1 sending in %s", __func__)); | ||
1803 | |||
1804 | packet_start(SSH2_MSG_USERAUTH_JPAKE_CLIENT_STEP1); | ||
1805 | packet_put_string(pctx->client_id, pctx->client_id_len); | ||
1806 | packet_put_bignum2(pctx->g_x1); | ||
1807 | packet_put_bignum2(pctx->g_x2); | ||
1808 | packet_put_string(x1_proof, x1_proof_len); | ||
1809 | packet_put_string(x2_proof, x2_proof_len); | ||
1810 | packet_send(); | ||
1811 | |||
1812 | bzero(x1_proof, x1_proof_len); | ||
1813 | bzero(x2_proof, x2_proof_len); | ||
1814 | xfree(x1_proof); | ||
1815 | xfree(x2_proof); | ||
1816 | |||
1817 | /* Expect step 1 packet from peer */ | ||
1818 | dispatch_set(SSH2_MSG_USERAUTH_JPAKE_SERVER_STEP1, | ||
1819 | input_userauth_jpake_server_step1); | ||
1820 | |||
1821 | return 1; | ||
1822 | } | ||
1823 | |||
1824 | void | ||
1825 | userauth_jpake_cleanup(Authctxt *authctxt) | ||
1826 | { | ||
1827 | debug3("%s: clean up", __func__); | ||
1828 | if (authctxt->methoddata != NULL) { | ||
1829 | jpake_free(authctxt->methoddata); | ||
1830 | authctxt->methoddata = NULL; | ||
1831 | } | ||
1832 | } | ||
1833 | #endif /* JPAKE */ | ||
1834 | |||
1516 | /* find auth method */ | 1835 | /* find auth method */ |
1517 | 1836 | ||
1518 | /* | 1837 | /* |
@@ -1614,3 +1933,4 @@ authmethods_get(void) | |||
1614 | buffer_free(&b); | 1933 | buffer_free(&b); |
1615 | return list; | 1934 | return list; |
1616 | } | 1935 | } |
1936 | |||