1 /* 2 * EAP peer method: EAP-pwd (RFC 5931) 3 * Copyright (c) 2010, Dan Harkins <dharkins@lounge.org> 4 * 5 * This software may be distributed under the terms of the BSD license. 6 * See README for more details. 7 */ 8 9 #include "includes.h" 10 11 #include "common.h" 12 #include "crypto/sha1.h" 13 #include "crypto/sha256.h" 14 #include "crypto/sha512.h" 15 #include "crypto/ms_funcs.h" 16 #include "crypto/crypto.h" 17 #include "eap_peer/eap_i.h" 18 #include "eap_common/eap_pwd_common.h" 19 20 21 struct eap_pwd_data { 22 enum { 23 PWD_ID_Req, PWD_Commit_Req, PWD_Confirm_Req, 24 SUCCESS_ON_FRAG_COMPLETION, SUCCESS, FAILURE 25 } state; 26 u8 *id_peer; 27 size_t id_peer_len; 28 u8 *id_server; 29 size_t id_server_len; 30 u8 *password; 31 size_t password_len; 32 int password_hash; 33 u16 group_num; 34 u8 prep; 35 u8 token[4]; 36 EAP_PWD_group *grp; 37 38 struct wpabuf *inbuf; 39 size_t in_frag_pos; 40 struct wpabuf *outbuf; 41 size_t out_frag_pos; 42 size_t mtu; 43 44 struct crypto_bignum *k; 45 struct crypto_bignum *private_value; 46 struct crypto_bignum *server_scalar; 47 struct crypto_bignum *my_scalar; 48 struct crypto_ec_point *my_element; 49 struct crypto_ec_point *server_element; 50 51 u8 msk[EAP_MSK_LEN]; 52 u8 emsk[EAP_EMSK_LEN]; 53 u8 session_id[1 + SHA256_MAC_LEN]; 54 }; 55 56 57 #ifndef CONFIG_NO_STDOUT_DEBUG 58 static const char * eap_pwd_state_txt(int state) 59 { 60 switch (state) { 61 case PWD_ID_Req: 62 return "PWD-ID-Req"; 63 case PWD_Commit_Req: 64 return "PWD-Commit-Req"; 65 case PWD_Confirm_Req: 66 return "PWD-Confirm-Req"; 67 case SUCCESS_ON_FRAG_COMPLETION: 68 return "SUCCESS_ON_FRAG_COMPLETION"; 69 case SUCCESS: 70 return "SUCCESS"; 71 case FAILURE: 72 return "FAILURE"; 73 default: 74 return "PWD-UNK"; 75 } 76 } 77 #endif /* CONFIG_NO_STDOUT_DEBUG */ 78 79 80 static void eap_pwd_state(struct eap_pwd_data *data, int state) 81 { 82 wpa_printf(MSG_DEBUG, "EAP-PWD: %s -> %s", 83 eap_pwd_state_txt(data->state), eap_pwd_state_txt(state)); 84 data->state = state; 85 } 86 87 88 static void * eap_pwd_init(struct eap_sm *sm) 89 { 90 struct eap_pwd_data *data; 91 const u8 *identity, *password; 92 size_t identity_len, password_len; 93 int fragment_size; 94 int pwhash; 95 96 password = eap_get_config_password2(sm, &password_len, &pwhash); 97 if (password == NULL) { 98 wpa_printf(MSG_INFO, "EAP-PWD: No password configured!"); 99 return NULL; 100 } 101 102 identity = eap_get_config_identity(sm, &identity_len); 103 if (identity == NULL) { 104 wpa_printf(MSG_INFO, "EAP-PWD: No identity configured!"); 105 return NULL; 106 } 107 108 if ((data = os_zalloc(sizeof(*data))) == NULL) { 109 wpa_printf(MSG_INFO, "EAP-PWD: memory allocation data fail"); 110 return NULL; 111 } 112 113 if ((data->id_peer = os_malloc(identity_len)) == NULL) { 114 wpa_printf(MSG_INFO, "EAP-PWD: memory allocation id fail"); 115 os_free(data); 116 return NULL; 117 } 118 119 os_memcpy(data->id_peer, identity, identity_len); 120 data->id_peer_len = identity_len; 121 122 if ((data->password = os_malloc(password_len)) == NULL) { 123 wpa_printf(MSG_INFO, "EAP-PWD: memory allocation psk fail"); 124 bin_clear_free(data->id_peer, data->id_peer_len); 125 os_free(data); 126 return NULL; 127 } 128 os_memcpy(data->password, password, password_len); 129 data->password_len = password_len; 130 data->password_hash = pwhash; 131 132 data->out_frag_pos = data->in_frag_pos = 0; 133 data->inbuf = data->outbuf = NULL; 134 fragment_size = eap_get_config_fragment_size(sm); 135 if (fragment_size <= 0) 136 data->mtu = 1020; /* default from RFC 5931 */ 137 else 138 data->mtu = fragment_size; 139 140 data->state = PWD_ID_Req; 141 142 return data; 143 } 144 145 146 static void eap_pwd_deinit(struct eap_sm *sm, void *priv) 147 { 148 struct eap_pwd_data *data = priv; 149 150 crypto_bignum_deinit(data->private_value, 1); 151 crypto_bignum_deinit(data->server_scalar, 1); 152 crypto_bignum_deinit(data->my_scalar, 1); 153 crypto_bignum_deinit(data->k, 1); 154 crypto_ec_point_deinit(data->my_element, 1); 155 crypto_ec_point_deinit(data->server_element, 1); 156 bin_clear_free(data->id_peer, data->id_peer_len); 157 bin_clear_free(data->id_server, data->id_server_len); 158 bin_clear_free(data->password, data->password_len); 159 if (data->grp) { 160 crypto_ec_deinit(data->grp->group); 161 crypto_ec_point_deinit(data->grp->pwe, 1); 162 os_free(data->grp); 163 } 164 wpabuf_free(data->inbuf); 165 wpabuf_free(data->outbuf); 166 bin_clear_free(data, sizeof(*data)); 167 } 168 169 170 static u8 * eap_pwd_getkey(struct eap_sm *sm, void *priv, size_t *len) 171 { 172 struct eap_pwd_data *data = priv; 173 u8 *key; 174 175 if (data->state != SUCCESS) 176 return NULL; 177 178 key = os_memdup(data->msk, EAP_MSK_LEN); 179 if (key == NULL) 180 return NULL; 181 182 *len = EAP_MSK_LEN; 183 184 return key; 185 } 186 187 188 static u8 * eap_pwd_get_session_id(struct eap_sm *sm, void *priv, size_t *len) 189 { 190 struct eap_pwd_data *data = priv; 191 u8 *id; 192 193 if (data->state != SUCCESS) 194 return NULL; 195 196 id = os_memdup(data->session_id, 1 + SHA256_MAC_LEN); 197 if (id == NULL) 198 return NULL; 199 200 *len = 1 + SHA256_MAC_LEN; 201 202 return id; 203 } 204 205 206 static void 207 eap_pwd_perform_id_exchange(struct eap_sm *sm, struct eap_pwd_data *data, 208 struct eap_method_ret *ret, 209 const struct wpabuf *reqData, 210 const u8 *payload, size_t payload_len) 211 { 212 struct eap_pwd_id *id; 213 214 if (data->state != PWD_ID_Req) { 215 ret->ignore = TRUE; 216 eap_pwd_state(data, FAILURE); 217 return; 218 } 219 220 if (payload_len < sizeof(struct eap_pwd_id)) { 221 ret->ignore = TRUE; 222 eap_pwd_state(data, FAILURE); 223 return; 224 } 225 226 id = (struct eap_pwd_id *) payload; 227 data->group_num = be_to_host16(id->group_num); 228 wpa_printf(MSG_DEBUG, 229 "EAP-PWD: Server EAP-pwd-ID proposal: group=%u random=%u prf=%u prep=%u", 230 data->group_num, id->random_function, id->prf, id->prep); 231 if ((id->random_function != EAP_PWD_DEFAULT_RAND_FUNC) || 232 (id->prf != EAP_PWD_DEFAULT_PRF)) { 233 ret->ignore = TRUE; 234 eap_pwd_state(data, FAILURE); 235 return; 236 } 237 238 if (id->prep != EAP_PWD_PREP_NONE && 239 id->prep != EAP_PWD_PREP_MS && 240 id->prep != EAP_PWD_PREP_SSHA1 && 241 id->prep != EAP_PWD_PREP_SSHA256 && 242 id->prep != EAP_PWD_PREP_SSHA512) { 243 wpa_printf(MSG_DEBUG, 244 "EAP-PWD: Unsupported password pre-processing technique (Prep=%u)", 245 id->prep); 246 eap_pwd_state(data, FAILURE); 247 return; 248 } 249 250 if (id->prep == EAP_PWD_PREP_NONE && data->password_hash) { 251 wpa_printf(MSG_DEBUG, 252 "EAP-PWD: Unhashed password not available"); 253 eap_pwd_state(data, FAILURE); 254 return; 255 } 256 257 wpa_printf(MSG_DEBUG, "EAP-PWD (peer): using group %d", 258 data->group_num); 259 260 data->prep = id->prep; 261 os_memcpy(data->token, id->token, sizeof(id->token)); 262 263 if (data->id_server || data->grp) { 264 wpa_printf(MSG_INFO, "EAP-pwd: data was already allocated"); 265 eap_pwd_state(data, FAILURE); 266 return; 267 } 268 269 data->id_server = os_malloc(payload_len - sizeof(struct eap_pwd_id)); 270 if (data->id_server == NULL) { 271 wpa_printf(MSG_INFO, "EAP-PWD: memory allocation id fail"); 272 eap_pwd_state(data, FAILURE); 273 return; 274 } 275 data->id_server_len = payload_len - sizeof(struct eap_pwd_id); 276 os_memcpy(data->id_server, id->identity, data->id_server_len); 277 wpa_hexdump_ascii(MSG_INFO, "EAP-PWD (peer): server sent id of", 278 data->id_server, data->id_server_len); 279 280 data->grp = get_eap_pwd_group(data->group_num); 281 if (data->grp == NULL) { 282 wpa_printf(MSG_INFO, "EAP-PWD: failed to allocate memory for " 283 "group"); 284 eap_pwd_state(data, FAILURE); 285 return; 286 } 287 288 data->outbuf = wpabuf_alloc(sizeof(struct eap_pwd_id) + 289 data->id_peer_len); 290 if (data->outbuf == NULL) { 291 eap_pwd_state(data, FAILURE); 292 return; 293 } 294 wpabuf_put_be16(data->outbuf, data->group_num); 295 wpabuf_put_u8(data->outbuf, EAP_PWD_DEFAULT_RAND_FUNC); 296 wpabuf_put_u8(data->outbuf, EAP_PWD_DEFAULT_PRF); 297 wpabuf_put_data(data->outbuf, id->token, sizeof(id->token)); 298 wpabuf_put_u8(data->outbuf, id->prep); 299 wpabuf_put_data(data->outbuf, data->id_peer, data->id_peer_len); 300 301 eap_pwd_state(data, PWD_Commit_Req); 302 } 303 304 305 static void 306 eap_pwd_perform_commit_exchange(struct eap_sm *sm, struct eap_pwd_data *data, 307 struct eap_method_ret *ret, 308 const struct wpabuf *reqData, 309 const u8 *payload, size_t payload_len) 310 { 311 struct crypto_ec_point *K = NULL, *point = NULL; 312 struct crypto_bignum *mask = NULL, *cofactor = NULL; 313 const u8 *ptr = payload; 314 u8 *scalar = NULL, *element = NULL; 315 size_t prime_len, order_len; 316 const u8 *password; 317 size_t password_len; 318 u8 pwhashhash[16]; 319 const u8 *salt_pwd[2]; 320 size_t salt_pwd_len[2], exp_len; 321 u8 salt_len, salthashpwd[64]; /* 64 = SHA512_DIGEST_LENGTH */ 322 int res; 323 324 if (data->state != PWD_Commit_Req) { 325 ret->ignore = TRUE; 326 goto fin; 327 } 328 329 if (!data->grp) { 330 wpa_printf(MSG_DEBUG, 331 "EAP-PWD (client): uninitialized EAP-pwd group"); 332 ret->ignore = TRUE; 333 goto fin; 334 } 335 336 prime_len = crypto_ec_prime_len(data->grp->group); 337 order_len = crypto_ec_order_len(data->grp->group); 338 339 switch (data->prep) { 340 case EAP_PWD_PREP_MS: 341 wpa_printf(MSG_DEBUG, 342 "EAP-pwd commit request, password prep is MS"); 343 #ifdef CONFIG_FIPS 344 wpa_printf(MSG_ERROR, 345 "EAP-PWD (peer): MS password hash not supported in FIPS mode"); 346 eap_pwd_state(data, FAILURE); 347 return; 348 #else /* CONFIG_FIPS */ 349 if (payload_len != 2 * prime_len + order_len) { 350 wpa_printf(MSG_INFO, 351 "EAP-pwd: Unexpected Commit payload length %u (expected %u)", 352 (unsigned int) payload_len, 353 (unsigned int) (2 * prime_len + order_len)); 354 goto fin; 355 } 356 if (data->password_hash) { 357 res = hash_nt_password_hash(data->password, pwhashhash); 358 } else { 359 u8 pwhash[16]; 360 361 res = nt_password_hash(data->password, 362 data->password_len, pwhash); 363 if (res == 0) 364 res = hash_nt_password_hash(pwhash, pwhashhash); 365 os_memset(pwhash, 0, sizeof(pwhash)); 366 } 367 368 if (res) { 369 eap_pwd_state(data, FAILURE); 370 return; 371 } 372 373 password = pwhashhash; 374 password_len = sizeof(pwhashhash); 375 #endif /* CONFIG_FIPS */ 376 break; 377 case EAP_PWD_PREP_SSHA1: 378 wpa_printf(MSG_DEBUG, 379 "EAP-pwd commit request, password prep is salted sha1"); 380 if (payload_len < 1 || *ptr == 0) { 381 wpa_printf(MSG_DEBUG, "EAP-pwd: Invalid Salt-len"); 382 goto fin; 383 } 384 salt_len = *ptr++; 385 exp_len = 1 + salt_len + 2 * prime_len + order_len; 386 if (payload_len != exp_len) { 387 wpa_printf(MSG_INFO, 388 "EAP-pwd: Unexpected Commit payload length %u (expected %u)", 389 (unsigned int) payload_len, 390 (unsigned int) exp_len); 391 goto fin; 392 } 393 394 /* salted-password = Hash(password | salt) */ 395 wpa_hexdump_key(MSG_DEBUG, "EAP-pwd: Unsalted password", 396 data->password, data->password_len); 397 wpa_hexdump(MSG_DEBUG, "EAP-pwd: Salt", ptr, salt_len); 398 salt_pwd[0] = data->password; 399 salt_pwd[1] = ptr; 400 salt_pwd_len[0] = data->password_len; 401 salt_pwd_len[1] = salt_len; 402 if (sha1_vector(2, salt_pwd, salt_pwd_len, salthashpwd) < 0) 403 goto fin; 404 405 wpa_printf(MSG_DEBUG, 406 "EAP-pwd: sha1 hashed %d byte salt with password", 407 (int) salt_len); 408 ptr += salt_len; 409 password = salthashpwd; 410 password_len = SHA1_MAC_LEN; 411 wpa_hexdump_key(MSG_DEBUG, "EAP-pwd: Salted password", 412 password, password_len); 413 break; 414 case EAP_PWD_PREP_SSHA256: 415 wpa_printf(MSG_DEBUG, 416 "EAP-pwd commit request, password prep is salted sha256"); 417 if (payload_len < 1 || *ptr == 0) { 418 wpa_printf(MSG_DEBUG, "EAP-pwd: Invalid Salt-len"); 419 goto fin; 420 } 421 salt_len = *ptr++; 422 exp_len = 1 + salt_len + 2 * prime_len + order_len; 423 if (payload_len != exp_len) { 424 wpa_printf(MSG_INFO, 425 "EAP-pwd: Unexpected Commit payload length %u (expected %u)", 426 (unsigned int) payload_len, 427 (unsigned int) exp_len); 428 goto fin; 429 } 430 431 /* salted-password = Hash(password | salt) */ 432 wpa_hexdump_key(MSG_DEBUG, "EAP-pwd: Unsalted password", 433 data->password, data->password_len); 434 wpa_hexdump(MSG_DEBUG, "EAP-pwd: Salt", ptr, salt_len); 435 salt_pwd[0] = data->password; 436 salt_pwd[1] = ptr; 437 salt_pwd_len[0] = data->password_len; 438 salt_pwd_len[1] = salt_len; 439 if (sha256_vector(2, salt_pwd, salt_pwd_len, salthashpwd) < 0) 440 goto fin; 441 442 ptr += salt_len; 443 password = salthashpwd; 444 password_len = SHA256_MAC_LEN; 445 wpa_hexdump_key(MSG_DEBUG, "EAP-pwd: Salted password", 446 password, password_len); 447 break; 448 #ifdef CONFIG_SHA512 449 case EAP_PWD_PREP_SSHA512: 450 wpa_printf(MSG_DEBUG, 451 "EAP-pwd commit request, password prep is salted sha512"); 452 if (payload_len < 1 || *ptr == 0) { 453 wpa_printf(MSG_DEBUG, "EAP-pwd: Invalid Salt-len"); 454 goto fin; 455 } 456 salt_len = *ptr++; 457 exp_len = 1 + salt_len + 2 * prime_len + order_len; 458 if (payload_len != exp_len) { 459 wpa_printf(MSG_INFO, 460 "EAP-pwd: Unexpected Commit payload length %u (expected %u)", 461 (unsigned int) payload_len, 462 (unsigned int) exp_len); 463 goto fin; 464 } 465 466 /* salted-password = Hash(password | salt) */ 467 wpa_hexdump_key(MSG_DEBUG, "EAP-pwd: Unsalted password", 468 data->password, data->password_len); 469 wpa_hexdump(MSG_DEBUG, "EAP-pwd: Salt", ptr, salt_len); 470 salt_pwd[0] = data->password; 471 salt_pwd[1] = ptr; 472 salt_pwd_len[0] = data->password_len; 473 salt_pwd_len[1] = salt_len; 474 if (sha512_vector(2, salt_pwd, salt_pwd_len, salthashpwd) < 0) 475 goto fin; 476 477 ptr += salt_len; 478 password = salthashpwd; 479 password_len = SHA512_MAC_LEN; 480 wpa_hexdump_key(MSG_DEBUG, "EAP-pwd: Salted password", 481 password, password_len); 482 break; 483 #endif /* CONFIG_SHA512 */ 484 case EAP_PWD_PREP_NONE: 485 wpa_printf(MSG_DEBUG, 486 "EAP-pwd commit request, password prep is NONE"); 487 if (data->password_hash) { 488 wpa_printf(MSG_DEBUG, 489 "EAP-PWD: Unhashed password not available"); 490 eap_pwd_state(data, FAILURE); 491 return; 492 } 493 if (payload_len != 2 * prime_len + order_len) { 494 wpa_printf(MSG_INFO, 495 "EAP-pwd: Unexpected Commit payload length %u (expected %u)", 496 (unsigned int) payload_len, 497 (unsigned int) (2 * prime_len + order_len)); 498 goto fin; 499 } 500 password = data->password; 501 password_len = data->password_len; 502 break; 503 default: 504 wpa_printf(MSG_DEBUG, 505 "EAP-pwd: Unsupported password pre-processing technique (Prep=%u)", 506 data->prep); 507 eap_pwd_state(data, FAILURE); 508 return; 509 } 510 511 /* compute PWE */ 512 res = compute_password_element(data->grp, data->group_num, 513 password, password_len, 514 data->id_server, data->id_server_len, 515 data->id_peer, data->id_peer_len, 516 data->token); 517 os_memset(pwhashhash, 0, sizeof(pwhashhash)); 518 os_memset(salthashpwd, 0, sizeof(salthashpwd)); 519 if (res) { 520 wpa_printf(MSG_INFO, "EAP-PWD (peer): unable to compute PWE"); 521 eap_pwd_state(data, FAILURE); 522 return; 523 } 524 525 wpa_printf(MSG_DEBUG, "EAP-PWD (peer): computed %d bit PWE...", 526 (int) crypto_ec_prime_len_bits(data->grp->group)); 527 528 data->private_value = crypto_bignum_init(); 529 data->my_element = crypto_ec_point_init(data->grp->group); 530 cofactor = crypto_bignum_init(); 531 data->my_scalar = crypto_bignum_init(); 532 mask = crypto_bignum_init(); 533 if (!data->private_value || !data->my_element || !cofactor || 534 !data->my_scalar || !mask) { 535 wpa_printf(MSG_INFO, "EAP-PWD (peer): scalar allocation fail"); 536 goto fin; 537 } 538 539 if (crypto_ec_cofactor(data->grp->group, cofactor) < 0) { 540 wpa_printf(MSG_INFO, "EAP-pwd (peer): unable to get cofactor " 541 "for curve"); 542 goto fin; 543 } 544 545 if (crypto_bignum_rand(data->private_value, 546 crypto_ec_get_order(data->grp->group)) < 0 || 547 crypto_bignum_rand(mask, 548 crypto_ec_get_order(data->grp->group)) < 0 || 549 crypto_bignum_add(data->private_value, mask, 550 data->my_scalar) < 0 || 551 crypto_bignum_mod(data->my_scalar, 552 crypto_ec_get_order(data->grp->group), 553 data->my_scalar) < 0) { 554 wpa_printf(MSG_INFO, 555 "EAP-pwd (peer): unable to get randomness"); 556 goto fin; 557 } 558 559 if (crypto_ec_point_mul(data->grp->group, data->grp->pwe, mask, 560 data->my_element) < 0) { 561 wpa_printf(MSG_INFO, "EAP-PWD (peer): element allocation " 562 "fail"); 563 eap_pwd_state(data, FAILURE); 564 goto fin; 565 } 566 567 if (crypto_ec_point_invert(data->grp->group, data->my_element) < 0) { 568 wpa_printf(MSG_INFO, "EAP-PWD (peer): element inversion fail"); 569 goto fin; 570 } 571 572 /* process the request */ 573 data->k = crypto_bignum_init(); 574 K = crypto_ec_point_init(data->grp->group); 575 point = crypto_ec_point_init(data->grp->group); 576 if (!data->k || !K || !point) { 577 wpa_printf(MSG_INFO, "EAP-PWD (peer): peer data allocation " 578 "fail"); 579 goto fin; 580 } 581 582 /* element, x then y, followed by scalar */ 583 data->server_element = crypto_ec_point_from_bin(data->grp->group, ptr); 584 if (!data->server_element) { 585 wpa_printf(MSG_INFO, "EAP-PWD (peer): setting peer element " 586 "fail"); 587 goto fin; 588 } 589 ptr += prime_len * 2; 590 data->server_scalar = crypto_bignum_init_set(ptr, order_len); 591 if (!data->server_scalar) { 592 wpa_printf(MSG_INFO, 593 "EAP-PWD (peer): setting peer scalar fail"); 594 goto fin; 595 } 596 597 /* check to ensure server's element is not in a small sub-group */ 598 if (!crypto_bignum_is_one(cofactor)) { 599 if (crypto_ec_point_mul(data->grp->group, data->server_element, 600 cofactor, point) < 0) { 601 wpa_printf(MSG_INFO, "EAP-PWD (peer): cannot multiply " 602 "server element by order!\n"); 603 goto fin; 604 } 605 if (crypto_ec_point_is_at_infinity(data->grp->group, point)) { 606 wpa_printf(MSG_INFO, "EAP-PWD (peer): server element " 607 "is at infinity!\n"); 608 goto fin; 609 } 610 } 611 612 /* compute the shared key, k */ 613 if (crypto_ec_point_mul(data->grp->group, data->grp->pwe, 614 data->server_scalar, K) < 0 || 615 crypto_ec_point_add(data->grp->group, K, data->server_element, 616 K) < 0 || 617 crypto_ec_point_mul(data->grp->group, K, data->private_value, 618 K) < 0) { 619 wpa_printf(MSG_INFO, "EAP-PWD (peer): computing shared key " 620 "fail"); 621 goto fin; 622 } 623 624 /* ensure that the shared key isn't in a small sub-group */ 625 if (!crypto_bignum_is_one(cofactor)) { 626 if (crypto_ec_point_mul(data->grp->group, K, cofactor, K) < 0) { 627 wpa_printf(MSG_INFO, "EAP-PWD (peer): cannot multiply " 628 "shared key point by order"); 629 goto fin; 630 } 631 } 632 633 /* 634 * This check is strictly speaking just for the case above where 635 * co-factor > 1 but it was suggested that even though this is probably 636 * never going to happen it is a simple and safe check "just to be 637 * sure" so let's be safe. 638 */ 639 if (crypto_ec_point_is_at_infinity(data->grp->group, K)) { 640 wpa_printf(MSG_INFO, "EAP-PWD (peer): shared key point is at " 641 "infinity!\n"); 642 goto fin; 643 } 644 645 if (crypto_ec_point_x(data->grp->group, K, data->k) < 0) { 646 wpa_printf(MSG_INFO, "EAP-PWD (peer): unable to extract " 647 "shared secret from point"); 648 goto fin; 649 } 650 651 /* now do the response */ 652 scalar = os_zalloc(order_len); 653 element = os_zalloc(prime_len * 2); 654 if (!scalar || !element) { 655 wpa_printf(MSG_INFO, "EAP-PWD (peer): data allocation fail"); 656 goto fin; 657 } 658 659 /* 660 * bignums occupy as little memory as possible so one that is 661 * sufficiently smaller than the prime or order might need pre-pending 662 * with zeros. 663 */ 664 crypto_bignum_to_bin(data->my_scalar, scalar, order_len, order_len); 665 if (crypto_ec_point_to_bin(data->grp->group, data->my_element, element, 666 element + prime_len) != 0) { 667 wpa_printf(MSG_INFO, "EAP-PWD (peer): point assignment fail"); 668 goto fin; 669 } 670 671 data->outbuf = wpabuf_alloc(order_len + 2 * prime_len); 672 if (data->outbuf == NULL) 673 goto fin; 674 675 /* we send the element as (x,y) follwed by the scalar */ 676 wpabuf_put_data(data->outbuf, element, 2 * prime_len); 677 wpabuf_put_data(data->outbuf, scalar, order_len); 678 679 fin: 680 os_free(scalar); 681 os_free(element); 682 crypto_bignum_deinit(mask, 1); 683 crypto_bignum_deinit(cofactor, 1); 684 crypto_ec_point_deinit(K, 1); 685 crypto_ec_point_deinit(point, 1); 686 if (data->outbuf == NULL) 687 eap_pwd_state(data, FAILURE); 688 else 689 eap_pwd_state(data, PWD_Confirm_Req); 690 } 691 692 693 static void 694 eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data, 695 struct eap_method_ret *ret, 696 const struct wpabuf *reqData, 697 const u8 *payload, size_t payload_len) 698 { 699 struct crypto_hash *hash = NULL; 700 u32 cs; 701 u16 grp; 702 u8 conf[SHA256_MAC_LEN], *cruft = NULL, *ptr; 703 size_t prime_len = 0, order_len = 0; 704 705 if (data->state != PWD_Confirm_Req) { 706 ret->ignore = TRUE; 707 goto fin; 708 } 709 710 if (payload_len != SHA256_MAC_LEN) { 711 wpa_printf(MSG_INFO, 712 "EAP-pwd: Unexpected Confirm payload length %u (expected %u)", 713 (unsigned int) payload_len, SHA256_MAC_LEN); 714 goto fin; 715 } 716 717 prime_len = crypto_ec_prime_len(data->grp->group); 718 order_len = crypto_ec_order_len(data->grp->group); 719 720 /* 721 * first build up the ciphersuite which is group | random_function | 722 * prf 723 */ 724 grp = htons(data->group_num); 725 ptr = (u8 *) &cs; 726 os_memcpy(ptr, &grp, sizeof(u16)); 727 ptr += sizeof(u16); 728 *ptr = EAP_PWD_DEFAULT_RAND_FUNC; 729 ptr += sizeof(u8); 730 *ptr = EAP_PWD_DEFAULT_PRF; 731 732 /* each component of the point will be at most as big as the prime */ 733 cruft = os_malloc(prime_len * 2); 734 if (!cruft) { 735 wpa_printf(MSG_INFO, "EAP-PWD (server): confirm allocation " 736 "fail"); 737 goto fin; 738 } 739 740 /* 741 * server's commit is H(k | server_element | server_scalar | 742 * peer_element | peer_scalar | ciphersuite) 743 */ 744 hash = eap_pwd_h_init(); 745 if (hash == NULL) 746 goto fin; 747 748 /* 749 * zero the memory each time because this is mod prime math and some 750 * value may start with a few zeros and the previous one did not. 751 */ 752 crypto_bignum_to_bin(data->k, cruft, prime_len, prime_len); 753 eap_pwd_h_update(hash, cruft, prime_len); 754 755 /* server element: x, y */ 756 if (crypto_ec_point_to_bin(data->grp->group, data->server_element, 757 cruft, cruft + prime_len) != 0) { 758 wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point " 759 "assignment fail"); 760 goto fin; 761 } 762 eap_pwd_h_update(hash, cruft, prime_len * 2); 763 764 /* server scalar */ 765 crypto_bignum_to_bin(data->server_scalar, cruft, order_len, order_len); 766 eap_pwd_h_update(hash, cruft, order_len); 767 768 /* my element: x, y */ 769 if (crypto_ec_point_to_bin(data->grp->group, data->my_element, cruft, 770 cruft + prime_len) != 0) { 771 wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point " 772 "assignment fail"); 773 goto fin; 774 } 775 eap_pwd_h_update(hash, cruft, prime_len * 2); 776 777 /* my scalar */ 778 crypto_bignum_to_bin(data->my_scalar, cruft, order_len, order_len); 779 eap_pwd_h_update(hash, cruft, order_len); 780 781 /* the ciphersuite */ 782 eap_pwd_h_update(hash, (u8 *) &cs, sizeof(u32)); 783 784 /* random function fin */ 785 eap_pwd_h_final(hash, conf); 786 hash = NULL; 787 788 ptr = (u8 *) payload; 789 if (os_memcmp_const(conf, ptr, SHA256_MAC_LEN)) { 790 wpa_printf(MSG_INFO, "EAP-PWD (peer): confirm did not verify"); 791 goto fin; 792 } 793 794 wpa_printf(MSG_DEBUG, "EAP-pwd (peer): confirm verified"); 795 796 /* 797 * compute confirm: 798 * H(k | peer_element | peer_scalar | server_element | server_scalar | 799 * ciphersuite) 800 */ 801 hash = eap_pwd_h_init(); 802 if (hash == NULL) 803 goto fin; 804 805 /* k */ 806 crypto_bignum_to_bin(data->k, cruft, prime_len, prime_len); 807 eap_pwd_h_update(hash, cruft, prime_len); 808 809 /* my element */ 810 if (crypto_ec_point_to_bin(data->grp->group, data->my_element, cruft, 811 cruft + prime_len) != 0) { 812 wpa_printf(MSG_INFO, "EAP-PWD (peer): confirm point " 813 "assignment fail"); 814 goto fin; 815 } 816 eap_pwd_h_update(hash, cruft, prime_len * 2); 817 818 /* my scalar */ 819 crypto_bignum_to_bin(data->my_scalar, cruft, order_len, order_len); 820 eap_pwd_h_update(hash, cruft, order_len); 821 822 /* server element: x, y */ 823 if (crypto_ec_point_to_bin(data->grp->group, data->server_element, 824 cruft, cruft + prime_len) != 0) { 825 wpa_printf(MSG_INFO, "EAP-PWD (peer): confirm point " 826 "assignment fail"); 827 goto fin; 828 } 829 eap_pwd_h_update(hash, cruft, prime_len * 2); 830 831 /* server scalar */ 832 crypto_bignum_to_bin(data->server_scalar, cruft, order_len, order_len); 833 eap_pwd_h_update(hash, cruft, order_len); 834 835 /* the ciphersuite */ 836 eap_pwd_h_update(hash, (u8 *) &cs, sizeof(u32)); 837 838 /* all done */ 839 eap_pwd_h_final(hash, conf); 840 hash = NULL; 841 842 if (compute_keys(data->grp, data->k, 843 data->my_scalar, data->server_scalar, conf, ptr, 844 &cs, data->msk, data->emsk, data->session_id) < 0) { 845 wpa_printf(MSG_INFO, "EAP-PWD (peer): unable to compute MSK | " 846 "EMSK"); 847 goto fin; 848 } 849 850 data->outbuf = wpabuf_alloc(SHA256_MAC_LEN); 851 if (data->outbuf == NULL) 852 goto fin; 853 854 wpabuf_put_data(data->outbuf, conf, SHA256_MAC_LEN); 855 856 fin: 857 bin_clear_free(cruft, prime_len * 2); 858 if (data->outbuf == NULL) { 859 ret->methodState = METHOD_DONE; 860 ret->decision = DECISION_FAIL; 861 eap_pwd_state(data, FAILURE); 862 } else { 863 eap_pwd_state(data, SUCCESS_ON_FRAG_COMPLETION); 864 } 865 866 /* clean allocated memory */ 867 if (hash) 868 eap_pwd_h_final(hash, conf); 869 } 870 871 872 static struct wpabuf * 873 eap_pwd_process(struct eap_sm *sm, void *priv, struct eap_method_ret *ret, 874 const struct wpabuf *reqData) 875 { 876 struct eap_pwd_data *data = priv; 877 struct wpabuf *resp = NULL; 878 const u8 *pos, *buf; 879 size_t len; 880 u16 tot_len = 0; 881 u8 lm_exch; 882 883 pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PWD, reqData, &len); 884 if ((pos == NULL) || (len < 1)) { 885 wpa_printf(MSG_DEBUG, "EAP-pwd: Got a frame but pos is %s and " 886 "len is %d", 887 pos == NULL ? "NULL" : "not NULL", (int) len); 888 ret->ignore = TRUE; 889 return NULL; 890 } 891 892 ret->ignore = FALSE; 893 ret->methodState = METHOD_MAY_CONT; 894 ret->decision = DECISION_FAIL; 895 ret->allowNotifications = FALSE; 896 897 lm_exch = *pos; 898 pos++; /* skip over the bits and the exch */ 899 len--; 900 901 /* 902 * we're fragmenting so send out the next fragment 903 */ 904 if (data->out_frag_pos) { 905 /* 906 * this should be an ACK 907 */ 908 if (len) 909 wpa_printf(MSG_INFO, "Bad Response! Fragmenting but " 910 "not an ACK"); 911 912 wpa_printf(MSG_DEBUG, "EAP-pwd: Got an ACK for a fragment"); 913 /* 914 * check if there are going to be more fragments 915 */ 916 len = wpabuf_len(data->outbuf) - data->out_frag_pos; 917 if ((len + EAP_PWD_HDR_SIZE) > data->mtu) { 918 len = data->mtu - EAP_PWD_HDR_SIZE; 919 EAP_PWD_SET_MORE_BIT(lm_exch); 920 } 921 resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD, 922 EAP_PWD_HDR_SIZE + len, 923 EAP_CODE_RESPONSE, eap_get_id(reqData)); 924 if (resp == NULL) { 925 wpa_printf(MSG_INFO, "Unable to allocate memory for " 926 "next fragment!"); 927 return NULL; 928 } 929 wpabuf_put_u8(resp, lm_exch); 930 buf = wpabuf_head_u8(data->outbuf); 931 wpabuf_put_data(resp, buf + data->out_frag_pos, len); 932 data->out_frag_pos += len; 933 /* 934 * this is the last fragment so get rid of the out buffer 935 */ 936 if (data->out_frag_pos >= wpabuf_len(data->outbuf)) { 937 wpabuf_free(data->outbuf); 938 data->outbuf = NULL; 939 data->out_frag_pos = 0; 940 } 941 wpa_printf(MSG_DEBUG, "EAP-pwd: Send %s fragment of %d bytes", 942 data->out_frag_pos == 0 ? "last" : "next", 943 (int) len); 944 if (data->state == SUCCESS_ON_FRAG_COMPLETION) { 945 ret->methodState = METHOD_DONE; 946 ret->decision = DECISION_UNCOND_SUCC; 947 eap_pwd_state(data, SUCCESS); 948 } 949 return resp; 950 } 951 952 /* 953 * see if this is a fragment that needs buffering 954 * 955 * if it's the first fragment there'll be a length field 956 */ 957 if (EAP_PWD_GET_LENGTH_BIT(lm_exch)) { 958 if (len < 2) { 959 wpa_printf(MSG_DEBUG, 960 "EAP-pwd: Frame too short to contain Total-Length field"); 961 ret->ignore = TRUE; 962 return NULL; 963 } 964 tot_len = WPA_GET_BE16(pos); 965 wpa_printf(MSG_DEBUG, "EAP-pwd: Incoming fragments whose " 966 "total length = %d", tot_len); 967 if (tot_len > 15000) 968 return NULL; 969 if (data->inbuf) { 970 wpa_printf(MSG_DEBUG, 971 "EAP-pwd: Unexpected new fragment start when previous fragment is still in use"); 972 ret->ignore = TRUE; 973 return NULL; 974 } 975 data->inbuf = wpabuf_alloc(tot_len); 976 if (data->inbuf == NULL) { 977 wpa_printf(MSG_INFO, "Out of memory to buffer " 978 "fragments!"); 979 return NULL; 980 } 981 data->in_frag_pos = 0; 982 pos += sizeof(u16); 983 len -= sizeof(u16); 984 } 985 /* 986 * buffer and ACK the fragment 987 */ 988 if (EAP_PWD_GET_MORE_BIT(lm_exch) || data->in_frag_pos) { 989 data->in_frag_pos += len; 990 if (data->in_frag_pos > wpabuf_size(data->inbuf)) { 991 wpa_printf(MSG_INFO, "EAP-pwd: Buffer overflow attack " 992 "detected (%d vs. %d)!", 993 (int) data->in_frag_pos, 994 (int) wpabuf_len(data->inbuf)); 995 wpabuf_free(data->inbuf); 996 data->inbuf = NULL; 997 data->in_frag_pos = 0; 998 return NULL; 999 } 1000 wpabuf_put_data(data->inbuf, pos, len); 1001 } 1002 if (EAP_PWD_GET_MORE_BIT(lm_exch)) { 1003 resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD, 1004 EAP_PWD_HDR_SIZE, 1005 EAP_CODE_RESPONSE, eap_get_id(reqData)); 1006 if (resp != NULL) 1007 wpabuf_put_u8(resp, (EAP_PWD_GET_EXCHANGE(lm_exch))); 1008 wpa_printf(MSG_DEBUG, "EAP-pwd: ACKing a %d byte fragment", 1009 (int) len); 1010 return resp; 1011 } 1012 /* 1013 * we're buffering and this is the last fragment 1014 */ 1015 if (data->in_frag_pos) { 1016 wpa_printf(MSG_DEBUG, "EAP-pwd: Last fragment, %d bytes", 1017 (int) len); 1018 pos = wpabuf_head_u8(data->inbuf); 1019 len = data->in_frag_pos; 1020 } 1021 wpa_printf(MSG_DEBUG, "EAP-pwd: processing frame: exch %d, len %d", 1022 EAP_PWD_GET_EXCHANGE(lm_exch), (int) len); 1023 1024 switch (EAP_PWD_GET_EXCHANGE(lm_exch)) { 1025 case EAP_PWD_OPCODE_ID_EXCH: 1026 eap_pwd_perform_id_exchange(sm, data, ret, reqData, 1027 pos, len); 1028 break; 1029 case EAP_PWD_OPCODE_COMMIT_EXCH: 1030 eap_pwd_perform_commit_exchange(sm, data, ret, reqData, 1031 pos, len); 1032 break; 1033 case EAP_PWD_OPCODE_CONFIRM_EXCH: 1034 eap_pwd_perform_confirm_exchange(sm, data, ret, reqData, 1035 pos, len); 1036 break; 1037 default: 1038 wpa_printf(MSG_INFO, "EAP-pwd: Ignoring message with unknown " 1039 "opcode %d", lm_exch); 1040 break; 1041 } 1042 /* 1043 * if we buffered the just processed input now's the time to free it 1044 */ 1045 if (data->in_frag_pos) { 1046 wpabuf_free(data->inbuf); 1047 data->inbuf = NULL; 1048 data->in_frag_pos = 0; 1049 } 1050 1051 if (data->outbuf == NULL) { 1052 ret->methodState = METHOD_DONE; 1053 ret->decision = DECISION_FAIL; 1054 return NULL; /* generic failure */ 1055 } 1056 1057 /* 1058 * we have output! Do we need to fragment it? 1059 */ 1060 lm_exch = EAP_PWD_GET_EXCHANGE(lm_exch); 1061 len = wpabuf_len(data->outbuf); 1062 if ((len + EAP_PWD_HDR_SIZE) > data->mtu) { 1063 resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD, data->mtu, 1064 EAP_CODE_RESPONSE, eap_get_id(reqData)); 1065 /* 1066 * if so it's the first so include a length field 1067 */ 1068 EAP_PWD_SET_LENGTH_BIT(lm_exch); 1069 EAP_PWD_SET_MORE_BIT(lm_exch); 1070 tot_len = len; 1071 /* 1072 * keep the packet at the MTU 1073 */ 1074 len = data->mtu - EAP_PWD_HDR_SIZE - sizeof(u16); 1075 wpa_printf(MSG_DEBUG, "EAP-pwd: Fragmenting output, total " 1076 "length = %d", tot_len); 1077 } else { 1078 resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD, 1079 EAP_PWD_HDR_SIZE + len, 1080 EAP_CODE_RESPONSE, eap_get_id(reqData)); 1081 } 1082 if (resp == NULL) 1083 return NULL; 1084 1085 wpabuf_put_u8(resp, lm_exch); 1086 if (EAP_PWD_GET_LENGTH_BIT(lm_exch)) { 1087 wpabuf_put_be16(resp, tot_len); 1088 data->out_frag_pos += len; 1089 } 1090 buf = wpabuf_head_u8(data->outbuf); 1091 wpabuf_put_data(resp, buf, len); 1092 /* 1093 * if we're not fragmenting then there's no need to carry this around 1094 */ 1095 if (data->out_frag_pos == 0) { 1096 wpabuf_free(data->outbuf); 1097 data->outbuf = NULL; 1098 data->out_frag_pos = 0; 1099 if (data->state == SUCCESS_ON_FRAG_COMPLETION) { 1100 ret->methodState = METHOD_DONE; 1101 ret->decision = DECISION_UNCOND_SUCC; 1102 eap_pwd_state(data, SUCCESS); 1103 } 1104 } 1105 1106 return resp; 1107 } 1108 1109 1110 static Boolean eap_pwd_key_available(struct eap_sm *sm, void *priv) 1111 { 1112 struct eap_pwd_data *data = priv; 1113 return data->state == SUCCESS; 1114 } 1115 1116 1117 static u8 * eap_pwd_get_emsk(struct eap_sm *sm, void *priv, size_t *len) 1118 { 1119 struct eap_pwd_data *data = priv; 1120 u8 *key; 1121 1122 if (data->state != SUCCESS) 1123 return NULL; 1124 1125 if ((key = os_malloc(EAP_EMSK_LEN)) == NULL) 1126 return NULL; 1127 1128 os_memcpy(key, data->emsk, EAP_EMSK_LEN); 1129 *len = EAP_EMSK_LEN; 1130 1131 return key; 1132 } 1133 1134 1135 int eap_peer_pwd_register(void) 1136 { 1137 struct eap_method *eap; 1138 1139 eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, 1140 EAP_VENDOR_IETF, EAP_TYPE_PWD, "PWD"); 1141 if (eap == NULL) 1142 return -1; 1143 1144 eap->init = eap_pwd_init; 1145 eap->deinit = eap_pwd_deinit; 1146 eap->process = eap_pwd_process; 1147 eap->isKeyAvailable = eap_pwd_key_available; 1148 eap->getKey = eap_pwd_getkey; 1149 eap->getSessionId = eap_pwd_get_session_id; 1150 eap->get_emsk = eap_pwd_get_emsk; 1151 1152 return eap_peer_method_register(eap); 1153 } 1154