1 /* $OpenBSD: auth2-jpake.c,v 1.4 2010/08/31 11:54:45 djm Exp $ */ 2 /* 3 * Copyright (c) 2008 Damien Miller. All rights reserved. 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 /* 19 * Server side of zero-knowledge password auth using J-PAKE protocol 20 * as described in: 21 * 22 * F. Hao, P. Ryan, "Password Authenticated Key Exchange by Juggling", 23 * 16th Workshop on Security Protocols, Cambridge, April 2008 24 * 25 * http://grouper.ieee.org/groups/1363/Research/contributions/hao-ryan-2008.pdf 26 */ 27 28 #ifdef JPAKE 29 30 #include <sys/types.h> 31 #include <sys/param.h> 32 33 #include <pwd.h> 34 #include <stdio.h> 35 #include <string.h> 36 #include <login_cap.h> 37 38 #include <openssl/bn.h> 39 #include <openssl/evp.h> 40 41 #include "xmalloc.h" 42 #include "ssh2.h" 43 #include "key.h" 44 #include "hostfile.h" 45 #include "auth.h" 46 #include "buffer.h" 47 #include "packet.h" 48 #include "dispatch.h" 49 #include "log.h" 50 #include "servconf.h" 51 #include "auth-options.h" 52 #include "canohost.h" 53 #ifdef GSSAPI 54 #include "ssh-gss.h" 55 #endif 56 #include "monitor_wrap.h" 57 58 #include "schnorr.h" 59 #include "jpake.h" 60 61 /* 62 * XXX options->permit_empty_passwd (at the moment, they will be refused 63 * anyway because they will mismatch on fake salt. 64 */ 65 66 /* Dispatch handlers */ 67 static void input_userauth_jpake_client_step1(int, u_int32_t, void *); 68 static void input_userauth_jpake_client_step2(int, u_int32_t, void *); 69 static void input_userauth_jpake_client_confirm(int, u_int32_t, void *); 70 71 static int auth2_jpake_start(Authctxt *); 72 73 /* import */ 74 extern ServerOptions options; 75 extern u_char *session_id2; 76 extern u_int session_id2_len; 77 78 /* 79 * Attempt J-PAKE authentication. 80 */ 81 static int 82 userauth_jpake(Authctxt *authctxt) 83 { 84 int authenticated = 0; 85 86 packet_check_eom(); 87 88 debug("jpake-01 (at) openssh.com requested"); 89 90 if (authctxt->user != NULL) { 91 if (authctxt->jpake_ctx == NULL) 92 authctxt->jpake_ctx = jpake_new(); 93 if (options.zero_knowledge_password_authentication) 94 authenticated = auth2_jpake_start(authctxt); 95 } 96 97 return authenticated; 98 } 99 100 Authmethod method_jpake = { 101 "jpake-01 (at) openssh.com", 102 userauth_jpake, 103 &options.zero_knowledge_password_authentication 104 }; 105 106 /* Clear context and callbacks */ 107 void 108 auth2_jpake_stop(Authctxt *authctxt) 109 { 110 /* unregister callbacks */ 111 dispatch_set(SSH2_MSG_USERAUTH_JPAKE_CLIENT_STEP1, NULL); 112 dispatch_set(SSH2_MSG_USERAUTH_JPAKE_CLIENT_STEP2, NULL); 113 dispatch_set(SSH2_MSG_USERAUTH_JPAKE_CLIENT_CONFIRM, NULL); 114 if (authctxt->jpake_ctx != NULL) { 115 jpake_free(authctxt->jpake_ctx); 116 authctxt->jpake_ctx = NULL; 117 } 118 } 119 120 /* Returns 1 if 'c' is a valid crypt(3) salt character, 0 otherwise */ 121 static int 122 valid_crypt_salt(int c) 123 { 124 if (c >= 'A' && c <= 'Z') 125 return 1; 126 if (c >= 'a' && c <= 'z') 127 return 1; 128 if (c >= '.' && c <= '9') 129 return 1; 130 return 0; 131 } 132 133 /* 134 * Derive fake salt as H(username || first_private_host_key) 135 * This provides relatively stable fake salts for non-existent 136 * users and avoids the jpake method becoming an account validity 137 * oracle. 138 */ 139 static void 140 derive_rawsalt(const char *username, u_char *rawsalt, u_int len) 141 { 142 u_char *digest; 143 u_int digest_len; 144 Buffer b; 145 Key *k; 146 147 buffer_init(&b); 148 buffer_put_cstring(&b, username); 149 if ((k = get_hostkey_by_index(0)) == NULL || 150 (k->flags & KEY_FLAG_EXT)) 151 fatal("%s: no hostkeys", __func__); 152 switch (k->type) { 153 case KEY_RSA1: 154 case KEY_RSA: 155 if (k->rsa->p == NULL || k->rsa->q == NULL) 156 fatal("%s: RSA key missing p and/or q", __func__); 157 buffer_put_bignum2(&b, k->rsa->p); 158 buffer_put_bignum2(&b, k->rsa->q); 159 break; 160 case KEY_DSA: 161 if (k->dsa->priv_key == NULL) 162 fatal("%s: DSA key missing priv_key", __func__); 163 buffer_put_bignum2(&b, k->dsa->priv_key); 164 break; 165 case KEY_ECDSA: 166 if (EC_KEY_get0_private_key(k->ecdsa) == NULL) 167 fatal("%s: ECDSA key missing priv_key", __func__); 168 buffer_put_bignum2(&b, EC_KEY_get0_private_key(k->ecdsa)); 169 break; 170 default: 171 fatal("%s: unknown key type %d", __func__, k->type); 172 } 173 if (hash_buffer(buffer_ptr(&b), buffer_len(&b), EVP_sha256(), 174 &digest, &digest_len) != 0) 175 fatal("%s: hash_buffer", __func__); 176 buffer_free(&b); 177 if (len > digest_len) 178 fatal("%s: not enough bytes for rawsalt (want %u have %u)", 179 __func__, len, digest_len); 180 memcpy(rawsalt, digest, len); 181 bzero(digest, digest_len); 182 xfree(digest); 183 } 184 185 /* ASCII an integer [0, 64) for inclusion in a password/salt */ 186 static char 187 pw_encode64(u_int i64) 188 { 189 const u_char e64[] = 190 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; 191 return e64[i64 % 64]; 192 } 193 194 /* Generate ASCII salt bytes for user */ 195 static char * 196 makesalt(u_int want, const char *user) 197 { 198 u_char rawsalt[32]; 199 static char ret[33]; 200 u_int i; 201 202 if (want > sizeof(ret) - 1) 203 fatal("%s: want %u", __func__, want); 204 205 derive_rawsalt(user, rawsalt, sizeof(rawsalt)); 206 bzero(ret, sizeof(ret)); 207 for (i = 0; i < want; i++) 208 ret[i] = pw_encode64(rawsalt[i]); 209 bzero(rawsalt, sizeof(rawsalt)); 210 211 return ret; 212 } 213 214 /* 215 * Select the system's default password hashing scheme and generate 216 * a stable fake salt under it for use by a non-existent account. 217 * Prevents jpake method being used to infer the validity of accounts. 218 */ 219 static void 220 fake_salt_and_scheme(Authctxt *authctxt, char **salt, char **scheme) 221 { 222 char *rounds_s, *style; 223 long long rounds; 224 login_cap_t *lc; 225 226 227 if ((lc = login_getclass(authctxt->pw->pw_class)) == NULL && 228 (lc = login_getclass(NULL)) == NULL) 229 fatal("%s: login_getclass failed", __func__); 230 style = login_getcapstr(lc, "localcipher", NULL, NULL); 231 if (style == NULL) 232 style = xstrdup("blowfish,6"); 233 login_close(lc); 234 235 if ((rounds_s = strchr(style, ',')) != NULL) 236 *rounds_s++ = '\0'; 237 rounds = strtonum(rounds_s, 1, 1<<31, NULL); 238 239 if (strcmp(style, "md5") == 0) { 240 xasprintf(salt, "$1$%s$", makesalt(8, authctxt->user)); 241 *scheme = xstrdup("md5"); 242 } else if (strcmp(style, "old") == 0) { 243 *salt = xstrdup(makesalt(2, authctxt->user)); 244 *scheme = xstrdup("crypt"); 245 } else if (strcmp(style, "newsalt") == 0) { 246 rounds = MAX(rounds, 7250); 247 rounds = MIN(rounds, (1<<24) - 1); 248 xasprintf(salt, "_%c%c%c%c%s", 249 pw_encode64(rounds), pw_encode64(rounds >> 6), 250 pw_encode64(rounds >> 12), pw_encode64(rounds >> 18), 251 makesalt(4, authctxt->user)); 252 *scheme = xstrdup("crypt-extended"); 253 } else { 254 /* Default to blowfish */ 255 rounds = MAX(rounds, 3); 256 rounds = MIN(rounds, 31); 257 xasprintf(salt, "$2a$%02lld$%s", rounds, 258 makesalt(22, authctxt->user)); 259 *scheme = xstrdup("bcrypt"); 260 } 261 xfree(style); 262 debug3("%s: fake %s salt for user %s: %s", 263 __func__, *scheme, authctxt->user, *salt); 264 } 265 266 /* 267 * Fetch password hashing scheme, password salt and derive shared secret 268 * for user. If user does not exist, a fake but stable and user-unique 269 * salt will be returned. 270 */ 271 void 272 auth2_jpake_get_pwdata(Authctxt *authctxt, BIGNUM **s, 273 char **hash_scheme, char **salt) 274 { 275 char *cp; 276 u_char *secret; 277 u_int secret_len, salt_len; 278 279 #ifdef JPAKE_DEBUG 280 debug3("%s: valid %d pw %.5s...", __func__, 281 authctxt->valid, authctxt->pw->pw_passwd); 282 #endif 283 284 *salt = NULL; 285 *hash_scheme = NULL; 286 if (authctxt->valid) { 287 if (strncmp(authctxt->pw->pw_passwd, "$2$", 3) == 0 && 288 strlen(authctxt->pw->pw_passwd) > 28) { 289 /* 290 * old-variant bcrypt: 291 * "$2$", 2 digit rounds, "$", 22 bytes salt 292 */ 293 salt_len = 3 + 2 + 1 + 22 + 1; 294 *salt = xmalloc(salt_len); 295 strlcpy(*salt, authctxt->pw->pw_passwd, salt_len); 296 *hash_scheme = xstrdup("bcrypt"); 297 } else if (strncmp(authctxt->pw->pw_passwd, "$2a$", 4) == 0 && 298 strlen(authctxt->pw->pw_passwd) > 29) { 299 /* 300 * current-variant bcrypt: 301 * "$2a$", 2 digit rounds, "$", 22 bytes salt 302 */ 303 salt_len = 4 + 2 + 1 + 22 + 1; 304 *salt = xmalloc(salt_len); 305 strlcpy(*salt, authctxt->pw->pw_passwd, salt_len); 306 *hash_scheme = xstrdup("bcrypt"); 307 } else if (strncmp(authctxt->pw->pw_passwd, "$1$", 3) == 0 && 308 strlen(authctxt->pw->pw_passwd) > 5) { 309 /* 310 * md5crypt: 311 * "$1$", salt until "$" 312 */ 313 cp = strchr(authctxt->pw->pw_passwd + 3, '$'); 314 if (cp != NULL) { 315 salt_len = (cp - authctxt->pw->pw_passwd) + 1; 316 *salt = xmalloc(salt_len); 317 strlcpy(*salt, authctxt->pw->pw_passwd, 318 salt_len); 319 *hash_scheme = xstrdup("md5crypt"); 320 } 321 } else if (strncmp(authctxt->pw->pw_passwd, "_", 1) == 0 && 322 strlen(authctxt->pw->pw_passwd) > 9) { 323 /* 324 * BSDI extended crypt: 325 * "_", 4 digits count, 4 chars salt 326 */ 327 salt_len = 1 + 4 + 4 + 1; 328 *salt = xmalloc(salt_len); 329 strlcpy(*salt, authctxt->pw->pw_passwd, salt_len); 330 *hash_scheme = xstrdup("crypt-extended"); 331 } else if (strlen(authctxt->pw->pw_passwd) == 13 && 332 valid_crypt_salt(authctxt->pw->pw_passwd[0]) && 333 valid_crypt_salt(authctxt->pw->pw_passwd[1])) { 334 /* 335 * traditional crypt: 336 * 2 chars salt 337 */ 338 salt_len = 2 + 1; 339 *salt = xmalloc(salt_len); 340 strlcpy(*salt, authctxt->pw->pw_passwd, salt_len); 341 *hash_scheme = xstrdup("crypt"); 342 } 343 if (*salt == NULL) { 344 debug("%s: unrecognised crypt scheme for user %s", 345 __func__, authctxt->pw->pw_name); 346 } 347 } 348 if (*salt == NULL) 349 fake_salt_and_scheme(authctxt, salt, hash_scheme); 350 351 if (hash_buffer(authctxt->pw->pw_passwd, 352 strlen(authctxt->pw->pw_passwd), EVP_sha256(), 353 &secret, &secret_len) != 0) 354 fatal("%s: hash_buffer", __func__); 355 if ((*s = BN_bin2bn(secret, secret_len, NULL)) == NULL) 356 fatal("%s: BN_bin2bn (secret)", __func__); 357 #ifdef JPAKE_DEBUG 358 debug3("%s: salt = %s (len %u)", __func__, 359 *salt, (u_int)strlen(*salt)); 360 debug3("%s: scheme = %s", __func__, *hash_scheme); 361 JPAKE_DEBUG_BN((*s, "%s: s = ", __func__)); 362 #endif 363 bzero(secret, secret_len); 364 xfree(secret); 365 } 366 367 /* 368 * Begin authentication attempt. 369 * Note, sets authctxt->postponed while in subprotocol 370 */ 371 static int 372 auth2_jpake_start(Authctxt *authctxt) 373 { 374 struct jpake_ctx *pctx = authctxt->jpake_ctx; 375 u_char *x3_proof, *x4_proof; 376 u_int x3_proof_len, x4_proof_len; 377 char *salt, *hash_scheme; 378 379 debug("%s: start", __func__); 380 381 PRIVSEP(jpake_step1(pctx->grp, 382 &pctx->server_id, &pctx->server_id_len, 383 &pctx->x3, &pctx->x4, &pctx->g_x3, &pctx->g_x4, 384 &x3_proof, &x3_proof_len, 385 &x4_proof, &x4_proof_len)); 386 387 PRIVSEP(auth2_jpake_get_pwdata(authctxt, &pctx->s, 388 &hash_scheme, &salt)); 389 390 if (!use_privsep) 391 JPAKE_DEBUG_CTX((pctx, "step 1 sending in %s", __func__)); 392 393 packet_start(SSH2_MSG_USERAUTH_JPAKE_SERVER_STEP1); 394 packet_put_cstring(hash_scheme); 395 packet_put_cstring(salt); 396 packet_put_string(pctx->server_id, pctx->server_id_len); 397 packet_put_bignum2(pctx->g_x3); 398 packet_put_bignum2(pctx->g_x4); 399 packet_put_string(x3_proof, x3_proof_len); 400 packet_put_string(x4_proof, x4_proof_len); 401 packet_send(); 402 packet_write_wait(); 403 404 bzero(hash_scheme, strlen(hash_scheme)); 405 bzero(salt, strlen(salt)); 406 xfree(hash_scheme); 407 xfree(salt); 408 bzero(x3_proof, x3_proof_len); 409 bzero(x4_proof, x4_proof_len); 410 xfree(x3_proof); 411 xfree(x4_proof); 412 413 /* Expect step 1 packet from peer */ 414 dispatch_set(SSH2_MSG_USERAUTH_JPAKE_CLIENT_STEP1, 415 input_userauth_jpake_client_step1); 416 417 authctxt->postponed = 1; 418 return 0; 419 } 420 421 /* ARGSUSED */ 422 static void 423 input_userauth_jpake_client_step1(int type, u_int32_t seq, void *ctxt) 424 { 425 Authctxt *authctxt = ctxt; 426 struct jpake_ctx *pctx = authctxt->jpake_ctx; 427 u_char *x1_proof, *x2_proof, *x4_s_proof; 428 u_int x1_proof_len, x2_proof_len, x4_s_proof_len; 429 430 /* Disable this message */ 431 dispatch_set(SSH2_MSG_USERAUTH_JPAKE_CLIENT_STEP1, NULL); 432 433 /* Fetch step 1 values */ 434 if ((pctx->g_x1 = BN_new()) == NULL || 435 (pctx->g_x2 = BN_new()) == NULL) 436 fatal("%s: BN_new", __func__); 437 pctx->client_id = packet_get_string(&pctx->client_id_len); 438 packet_get_bignum2(pctx->g_x1); 439 packet_get_bignum2(pctx->g_x2); 440 x1_proof = packet_get_string(&x1_proof_len); 441 x2_proof = packet_get_string(&x2_proof_len); 442 packet_check_eom(); 443 444 if (!use_privsep) 445 JPAKE_DEBUG_CTX((pctx, "step 1 received in %s", __func__)); 446 447 PRIVSEP(jpake_step2(pctx->grp, pctx->s, pctx->g_x3, 448 pctx->g_x1, pctx->g_x2, pctx->x4, 449 pctx->client_id, pctx->client_id_len, 450 pctx->server_id, pctx->server_id_len, 451 x1_proof, x1_proof_len, 452 x2_proof, x2_proof_len, 453 &pctx->b, 454 &x4_s_proof, &x4_s_proof_len)); 455 456 bzero(x1_proof, x1_proof_len); 457 bzero(x2_proof, x2_proof_len); 458 xfree(x1_proof); 459 xfree(x2_proof); 460 461 if (!use_privsep) 462 JPAKE_DEBUG_CTX((pctx, "step 2 sending in %s", __func__)); 463 464 /* Send values for step 2 */ 465 packet_start(SSH2_MSG_USERAUTH_JPAKE_SERVER_STEP2); 466 packet_put_bignum2(pctx->b); 467 packet_put_string(x4_s_proof, x4_s_proof_len); 468 packet_send(); 469 packet_write_wait(); 470 471 bzero(x4_s_proof, x4_s_proof_len); 472 xfree(x4_s_proof); 473 474 /* Expect step 2 packet from peer */ 475 dispatch_set(SSH2_MSG_USERAUTH_JPAKE_CLIENT_STEP2, 476 input_userauth_jpake_client_step2); 477 } 478 479 /* ARGSUSED */ 480 static void 481 input_userauth_jpake_client_step2(int type, u_int32_t seq, void *ctxt) 482 { 483 Authctxt *authctxt = ctxt; 484 struct jpake_ctx *pctx = authctxt->jpake_ctx; 485 u_char *x2_s_proof; 486 u_int x2_s_proof_len; 487 488 /* Disable this message */ 489 dispatch_set(SSH2_MSG_USERAUTH_JPAKE_CLIENT_STEP2, NULL); 490 491 if ((pctx->a = BN_new()) == NULL) 492 fatal("%s: BN_new", __func__); 493 494 /* Fetch step 2 values */ 495 packet_get_bignum2(pctx->a); 496 x2_s_proof = packet_get_string(&x2_s_proof_len); 497 packet_check_eom(); 498 499 if (!use_privsep) 500 JPAKE_DEBUG_CTX((pctx, "step 2 received in %s", __func__)); 501 502 /* Derive shared key and calculate confirmation hash */ 503 PRIVSEP(jpake_key_confirm(pctx->grp, pctx->s, pctx->a, 504 pctx->x4, pctx->g_x3, pctx->g_x4, pctx->g_x1, pctx->g_x2, 505 pctx->server_id, pctx->server_id_len, 506 pctx->client_id, pctx->client_id_len, 507 session_id2, session_id2_len, 508 x2_s_proof, x2_s_proof_len, 509 &pctx->k, 510 &pctx->h_k_sid_sessid, &pctx->h_k_sid_sessid_len)); 511 512 bzero(x2_s_proof, x2_s_proof_len); 513 xfree(x2_s_proof); 514 515 if (!use_privsep) 516 JPAKE_DEBUG_CTX((pctx, "confirm sending in %s", __func__)); 517 518 /* Send key confirmation proof */ 519 packet_start(SSH2_MSG_USERAUTH_JPAKE_SERVER_CONFIRM); 520 packet_put_string(pctx->h_k_sid_sessid, pctx->h_k_sid_sessid_len); 521 packet_send(); 522 packet_write_wait(); 523 524 /* Expect confirmation from peer */ 525 dispatch_set(SSH2_MSG_USERAUTH_JPAKE_CLIENT_CONFIRM, 526 input_userauth_jpake_client_confirm); 527 } 528 529 /* ARGSUSED */ 530 static void 531 input_userauth_jpake_client_confirm(int type, u_int32_t seq, void *ctxt) 532 { 533 Authctxt *authctxt = ctxt; 534 struct jpake_ctx *pctx = authctxt->jpake_ctx; 535 int authenticated = 0; 536 537 /* Disable this message */ 538 dispatch_set(SSH2_MSG_USERAUTH_JPAKE_CLIENT_CONFIRM, NULL); 539 540 pctx->h_k_cid_sessid = packet_get_string(&pctx->h_k_cid_sessid_len); 541 packet_check_eom(); 542 543 if (!use_privsep) 544 JPAKE_DEBUG_CTX((pctx, "confirm received in %s", __func__)); 545 546 /* Verify expected confirmation hash */ 547 if (PRIVSEP(jpake_check_confirm(pctx->k, 548 pctx->client_id, pctx->client_id_len, 549 session_id2, session_id2_len, 550 pctx->h_k_cid_sessid, pctx->h_k_cid_sessid_len)) == 1) 551 authenticated = authctxt->valid ? 1 : 0; 552 else 553 debug("%s: confirmation mismatch", __func__); 554 555 /* done */ 556 authctxt->postponed = 0; 557 jpake_free(authctxt->jpake_ctx); 558 authctxt->jpake_ctx = NULL; 559 userauth_finish(authctxt, authenticated, method_jpake.name); 560 } 561 562 #endif /* JPAKE */ 563 564