eap_pwd.c revision 1.8
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 21struct 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 58static 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 80static 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 88static 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 146static 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 170static 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 188static 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 206static void 207eap_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 305static void 306eap_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; 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 if (!data->k || !K) { 576 wpa_printf(MSG_INFO, "EAP-PWD (peer): peer data allocation " 577 "fail"); 578 goto fin; 579 } 580 581 /* element, x then y, followed by scalar */ 582 data->server_element = eap_pwd_get_element(data->grp, ptr); 583 if (!data->server_element) { 584 wpa_printf(MSG_INFO, "EAP-PWD (peer): setting peer element " 585 "fail"); 586 goto fin; 587 } 588 ptr += prime_len * 2; 589 data->server_scalar = eap_pwd_get_scalar(data->grp, ptr); 590 if (!data->server_scalar) { 591 wpa_printf(MSG_INFO, 592 "EAP-PWD (peer): setting peer scalar fail"); 593 goto fin; 594 } 595 596 /* compute the shared key, k */ 597 if (crypto_ec_point_mul(data->grp->group, data->grp->pwe, 598 data->server_scalar, K) < 0 || 599 crypto_ec_point_add(data->grp->group, K, data->server_element, 600 K) < 0 || 601 crypto_ec_point_mul(data->grp->group, K, data->private_value, 602 K) < 0) { 603 wpa_printf(MSG_INFO, "EAP-PWD (peer): computing shared key " 604 "fail"); 605 goto fin; 606 } 607 608 /* ensure that the shared key isn't in a small sub-group */ 609 if (!crypto_bignum_is_one(cofactor)) { 610 if (crypto_ec_point_mul(data->grp->group, K, cofactor, K) < 0) { 611 wpa_printf(MSG_INFO, "EAP-PWD (peer): cannot multiply " 612 "shared key point by order"); 613 goto fin; 614 } 615 } 616 617 /* 618 * This check is strictly speaking just for the case above where 619 * co-factor > 1 but it was suggested that even though this is probably 620 * never going to happen it is a simple and safe check "just to be 621 * sure" so let's be safe. 622 */ 623 if (crypto_ec_point_is_at_infinity(data->grp->group, K)) { 624 wpa_printf(MSG_INFO, "EAP-PWD (peer): shared key point is at " 625 "infinity!\n"); 626 goto fin; 627 } 628 629 if (crypto_ec_point_x(data->grp->group, K, data->k) < 0) { 630 wpa_printf(MSG_INFO, "EAP-PWD (peer): unable to extract " 631 "shared secret from point"); 632 goto fin; 633 } 634 635 /* now do the response */ 636 scalar = os_zalloc(order_len); 637 element = os_zalloc(prime_len * 2); 638 if (!scalar || !element) { 639 wpa_printf(MSG_INFO, "EAP-PWD (peer): data allocation fail"); 640 goto fin; 641 } 642 643 /* 644 * bignums occupy as little memory as possible so one that is 645 * sufficiently smaller than the prime or order might need pre-pending 646 * with zeros. 647 */ 648 crypto_bignum_to_bin(data->my_scalar, scalar, order_len, order_len); 649 if (crypto_ec_point_to_bin(data->grp->group, data->my_element, element, 650 element + prime_len) != 0) { 651 wpa_printf(MSG_INFO, "EAP-PWD (peer): point assignment fail"); 652 goto fin; 653 } 654 655 data->outbuf = wpabuf_alloc(order_len + 2 * prime_len); 656 if (data->outbuf == NULL) 657 goto fin; 658 659 /* we send the element as (x,y) follwed by the scalar */ 660 wpabuf_put_data(data->outbuf, element, 2 * prime_len); 661 wpabuf_put_data(data->outbuf, scalar, order_len); 662 663fin: 664 os_free(scalar); 665 os_free(element); 666 crypto_bignum_deinit(mask, 1); 667 crypto_bignum_deinit(cofactor, 1); 668 crypto_ec_point_deinit(K, 1); 669 if (data->outbuf == NULL) 670 eap_pwd_state(data, FAILURE); 671 else 672 eap_pwd_state(data, PWD_Confirm_Req); 673} 674 675 676static void 677eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data, 678 struct eap_method_ret *ret, 679 const struct wpabuf *reqData, 680 const u8 *payload, size_t payload_len) 681{ 682 struct crypto_hash *hash = NULL; 683 u32 cs; 684 u16 grp; 685 u8 conf[SHA256_MAC_LEN], *cruft = NULL, *ptr; 686 size_t prime_len = 0, order_len = 0; 687 688 if (data->state != PWD_Confirm_Req) { 689 ret->ignore = TRUE; 690 goto fin; 691 } 692 693 if (payload_len != SHA256_MAC_LEN) { 694 wpa_printf(MSG_INFO, 695 "EAP-pwd: Unexpected Confirm payload length %u (expected %u)", 696 (unsigned int) payload_len, SHA256_MAC_LEN); 697 goto fin; 698 } 699 700 prime_len = crypto_ec_prime_len(data->grp->group); 701 order_len = crypto_ec_order_len(data->grp->group); 702 703 /* 704 * first build up the ciphersuite which is group | random_function | 705 * prf 706 */ 707 grp = htons(data->group_num); 708 ptr = (u8 *) &cs; 709 os_memcpy(ptr, &grp, sizeof(u16)); 710 ptr += sizeof(u16); 711 *ptr = EAP_PWD_DEFAULT_RAND_FUNC; 712 ptr += sizeof(u8); 713 *ptr = EAP_PWD_DEFAULT_PRF; 714 715 /* each component of the point will be at most as big as the prime */ 716 cruft = os_malloc(prime_len * 2); 717 if (!cruft) { 718 wpa_printf(MSG_INFO, "EAP-PWD (server): confirm allocation " 719 "fail"); 720 goto fin; 721 } 722 723 /* 724 * server's commit is H(k | server_element | server_scalar | 725 * peer_element | peer_scalar | ciphersuite) 726 */ 727 hash = eap_pwd_h_init(); 728 if (hash == NULL) 729 goto fin; 730 731 /* 732 * zero the memory each time because this is mod prime math and some 733 * value may start with a few zeros and the previous one did not. 734 */ 735 crypto_bignum_to_bin(data->k, cruft, prime_len, prime_len); 736 eap_pwd_h_update(hash, cruft, prime_len); 737 738 /* server element: x, y */ 739 if (crypto_ec_point_to_bin(data->grp->group, data->server_element, 740 cruft, cruft + prime_len) != 0) { 741 wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point " 742 "assignment fail"); 743 goto fin; 744 } 745 eap_pwd_h_update(hash, cruft, prime_len * 2); 746 747 /* server scalar */ 748 crypto_bignum_to_bin(data->server_scalar, cruft, order_len, order_len); 749 eap_pwd_h_update(hash, cruft, order_len); 750 751 /* my element: x, y */ 752 if (crypto_ec_point_to_bin(data->grp->group, data->my_element, cruft, 753 cruft + prime_len) != 0) { 754 wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point " 755 "assignment fail"); 756 goto fin; 757 } 758 eap_pwd_h_update(hash, cruft, prime_len * 2); 759 760 /* my scalar */ 761 crypto_bignum_to_bin(data->my_scalar, cruft, order_len, order_len); 762 eap_pwd_h_update(hash, cruft, order_len); 763 764 /* the ciphersuite */ 765 eap_pwd_h_update(hash, (u8 *) &cs, sizeof(u32)); 766 767 /* random function fin */ 768 eap_pwd_h_final(hash, conf); 769 hash = NULL; 770 771 ptr = (u8 *) payload; 772 if (os_memcmp_const(conf, ptr, SHA256_MAC_LEN)) { 773 wpa_printf(MSG_INFO, "EAP-PWD (peer): confirm did not verify"); 774 goto fin; 775 } 776 777 wpa_printf(MSG_DEBUG, "EAP-pwd (peer): confirm verified"); 778 779 /* 780 * compute confirm: 781 * H(k | peer_element | peer_scalar | server_element | server_scalar | 782 * ciphersuite) 783 */ 784 hash = eap_pwd_h_init(); 785 if (hash == NULL) 786 goto fin; 787 788 /* k */ 789 crypto_bignum_to_bin(data->k, cruft, prime_len, prime_len); 790 eap_pwd_h_update(hash, cruft, prime_len); 791 792 /* my element */ 793 if (crypto_ec_point_to_bin(data->grp->group, data->my_element, cruft, 794 cruft + prime_len) != 0) { 795 wpa_printf(MSG_INFO, "EAP-PWD (peer): confirm point " 796 "assignment fail"); 797 goto fin; 798 } 799 eap_pwd_h_update(hash, cruft, prime_len * 2); 800 801 /* my scalar */ 802 crypto_bignum_to_bin(data->my_scalar, cruft, order_len, order_len); 803 eap_pwd_h_update(hash, cruft, order_len); 804 805 /* server element: x, y */ 806 if (crypto_ec_point_to_bin(data->grp->group, data->server_element, 807 cruft, cruft + prime_len) != 0) { 808 wpa_printf(MSG_INFO, "EAP-PWD (peer): confirm point " 809 "assignment fail"); 810 goto fin; 811 } 812 eap_pwd_h_update(hash, cruft, prime_len * 2); 813 814 /* server scalar */ 815 crypto_bignum_to_bin(data->server_scalar, cruft, order_len, order_len); 816 eap_pwd_h_update(hash, cruft, order_len); 817 818 /* the ciphersuite */ 819 eap_pwd_h_update(hash, (u8 *) &cs, sizeof(u32)); 820 821 /* all done */ 822 eap_pwd_h_final(hash, conf); 823 hash = NULL; 824 825 if (compute_keys(data->grp, data->k, 826 data->my_scalar, data->server_scalar, conf, ptr, 827 &cs, data->msk, data->emsk, data->session_id) < 0) { 828 wpa_printf(MSG_INFO, "EAP-PWD (peer): unable to compute MSK | " 829 "EMSK"); 830 goto fin; 831 } 832 833 data->outbuf = wpabuf_alloc(SHA256_MAC_LEN); 834 if (data->outbuf == NULL) 835 goto fin; 836 837 wpabuf_put_data(data->outbuf, conf, SHA256_MAC_LEN); 838 839fin: 840 bin_clear_free(cruft, prime_len * 2); 841 if (data->outbuf == NULL) { 842 ret->methodState = METHOD_DONE; 843 ret->decision = DECISION_FAIL; 844 eap_pwd_state(data, FAILURE); 845 } else { 846 eap_pwd_state(data, SUCCESS_ON_FRAG_COMPLETION); 847 } 848 849 /* clean allocated memory */ 850 if (hash) 851 eap_pwd_h_final(hash, conf); 852} 853 854 855static struct wpabuf * 856eap_pwd_process(struct eap_sm *sm, void *priv, struct eap_method_ret *ret, 857 const struct wpabuf *reqData) 858{ 859 struct eap_pwd_data *data = priv; 860 struct wpabuf *resp = NULL; 861 const u8 *pos, *buf; 862 size_t len; 863 u16 tot_len = 0; 864 u8 lm_exch; 865 866 pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PWD, reqData, &len); 867 if ((pos == NULL) || (len < 1)) { 868 wpa_printf(MSG_DEBUG, "EAP-pwd: Got a frame but pos is %s and " 869 "len is %d", 870 pos == NULL ? "NULL" : "not NULL", (int) len); 871 ret->ignore = TRUE; 872 return NULL; 873 } 874 875 ret->ignore = FALSE; 876 ret->methodState = METHOD_MAY_CONT; 877 ret->decision = DECISION_FAIL; 878 ret->allowNotifications = FALSE; 879 880 lm_exch = *pos; 881 pos++; /* skip over the bits and the exch */ 882 len--; 883 884 /* 885 * we're fragmenting so send out the next fragment 886 */ 887 if (data->out_frag_pos) { 888 /* 889 * this should be an ACK 890 */ 891 if (len) 892 wpa_printf(MSG_INFO, "Bad Response! Fragmenting but " 893 "not an ACK"); 894 895 wpa_printf(MSG_DEBUG, "EAP-pwd: Got an ACK for a fragment"); 896 /* 897 * check if there are going to be more fragments 898 */ 899 len = wpabuf_len(data->outbuf) - data->out_frag_pos; 900 if ((len + EAP_PWD_HDR_SIZE) > data->mtu) { 901 len = data->mtu - EAP_PWD_HDR_SIZE; 902 EAP_PWD_SET_MORE_BIT(lm_exch); 903 } 904 resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD, 905 EAP_PWD_HDR_SIZE + len, 906 EAP_CODE_RESPONSE, eap_get_id(reqData)); 907 if (resp == NULL) { 908 wpa_printf(MSG_INFO, "Unable to allocate memory for " 909 "next fragment!"); 910 return NULL; 911 } 912 wpabuf_put_u8(resp, lm_exch); 913 buf = wpabuf_head_u8(data->outbuf); 914 wpabuf_put_data(resp, buf + data->out_frag_pos, len); 915 data->out_frag_pos += len; 916 /* 917 * this is the last fragment so get rid of the out buffer 918 */ 919 if (data->out_frag_pos >= wpabuf_len(data->outbuf)) { 920 wpabuf_free(data->outbuf); 921 data->outbuf = NULL; 922 data->out_frag_pos = 0; 923 } 924 wpa_printf(MSG_DEBUG, "EAP-pwd: Send %s fragment of %d bytes", 925 data->out_frag_pos == 0 ? "last" : "next", 926 (int) len); 927 if (data->state == SUCCESS_ON_FRAG_COMPLETION) { 928 ret->methodState = METHOD_DONE; 929 ret->decision = DECISION_UNCOND_SUCC; 930 eap_pwd_state(data, SUCCESS); 931 } 932 return resp; 933 } 934 935 /* 936 * see if this is a fragment that needs buffering 937 * 938 * if it's the first fragment there'll be a length field 939 */ 940 if (EAP_PWD_GET_LENGTH_BIT(lm_exch)) { 941 if (len < 2) { 942 wpa_printf(MSG_DEBUG, 943 "EAP-pwd: Frame too short to contain Total-Length field"); 944 ret->ignore = TRUE; 945 return NULL; 946 } 947 tot_len = WPA_GET_BE16(pos); 948 wpa_printf(MSG_DEBUG, "EAP-pwd: Incoming fragments whose " 949 "total length = %d", tot_len); 950 if (tot_len > 15000) 951 return NULL; 952 if (data->inbuf) { 953 wpa_printf(MSG_DEBUG, 954 "EAP-pwd: Unexpected new fragment start when previous fragment is still in use"); 955 ret->ignore = TRUE; 956 return NULL; 957 } 958 data->inbuf = wpabuf_alloc(tot_len); 959 if (data->inbuf == NULL) { 960 wpa_printf(MSG_INFO, "Out of memory to buffer " 961 "fragments!"); 962 return NULL; 963 } 964 data->in_frag_pos = 0; 965 pos += sizeof(u16); 966 len -= sizeof(u16); 967 } 968 /* 969 * buffer and ACK the fragment 970 */ 971 if (EAP_PWD_GET_MORE_BIT(lm_exch) || data->in_frag_pos) { 972 data->in_frag_pos += len; 973 if (data->in_frag_pos > wpabuf_size(data->inbuf)) { 974 wpa_printf(MSG_INFO, "EAP-pwd: Buffer overflow attack " 975 "detected (%d vs. %d)!", 976 (int) data->in_frag_pos, 977 (int) wpabuf_len(data->inbuf)); 978 wpabuf_free(data->inbuf); 979 data->inbuf = NULL; 980 data->in_frag_pos = 0; 981 return NULL; 982 } 983 wpabuf_put_data(data->inbuf, pos, len); 984 } 985 if (EAP_PWD_GET_MORE_BIT(lm_exch)) { 986 resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD, 987 EAP_PWD_HDR_SIZE, 988 EAP_CODE_RESPONSE, eap_get_id(reqData)); 989 if (resp != NULL) 990 wpabuf_put_u8(resp, (EAP_PWD_GET_EXCHANGE(lm_exch))); 991 wpa_printf(MSG_DEBUG, "EAP-pwd: ACKing a %d byte fragment", 992 (int) len); 993 return resp; 994 } 995 /* 996 * we're buffering and this is the last fragment 997 */ 998 if (data->in_frag_pos) { 999 wpa_printf(MSG_DEBUG, "EAP-pwd: Last fragment, %d bytes", 1000 (int) len); 1001 pos = wpabuf_head_u8(data->inbuf); 1002 len = data->in_frag_pos; 1003 } 1004 wpa_printf(MSG_DEBUG, "EAP-pwd: processing frame: exch %d, len %d", 1005 EAP_PWD_GET_EXCHANGE(lm_exch), (int) len); 1006 1007 switch (EAP_PWD_GET_EXCHANGE(lm_exch)) { 1008 case EAP_PWD_OPCODE_ID_EXCH: 1009 eap_pwd_perform_id_exchange(sm, data, ret, reqData, 1010 pos, len); 1011 break; 1012 case EAP_PWD_OPCODE_COMMIT_EXCH: 1013 eap_pwd_perform_commit_exchange(sm, data, ret, reqData, 1014 pos, len); 1015 break; 1016 case EAP_PWD_OPCODE_CONFIRM_EXCH: 1017 eap_pwd_perform_confirm_exchange(sm, data, ret, reqData, 1018 pos, len); 1019 break; 1020 default: 1021 wpa_printf(MSG_INFO, "EAP-pwd: Ignoring message with unknown " 1022 "opcode %d", lm_exch); 1023 break; 1024 } 1025 /* 1026 * if we buffered the just processed input now's the time to free it 1027 */ 1028 if (data->in_frag_pos) { 1029 wpabuf_free(data->inbuf); 1030 data->inbuf = NULL; 1031 data->in_frag_pos = 0; 1032 } 1033 1034 if (data->outbuf == NULL) { 1035 ret->methodState = METHOD_DONE; 1036 ret->decision = DECISION_FAIL; 1037 return NULL; /* generic failure */ 1038 } 1039 1040 /* 1041 * we have output! Do we need to fragment it? 1042 */ 1043 lm_exch = EAP_PWD_GET_EXCHANGE(lm_exch); 1044 len = wpabuf_len(data->outbuf); 1045 lm_exch = EAP_PWD_GET_EXCHANGE(lm_exch); 1046 if ((len + EAP_PWD_HDR_SIZE) > data->mtu) { 1047 resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD, data->mtu, 1048 EAP_CODE_RESPONSE, eap_get_id(reqData)); 1049 /* 1050 * if so it's the first so include a length field 1051 */ 1052 EAP_PWD_SET_LENGTH_BIT(lm_exch); 1053 EAP_PWD_SET_MORE_BIT(lm_exch); 1054 tot_len = len; 1055 /* 1056 * keep the packet at the MTU 1057 */ 1058 len = data->mtu - EAP_PWD_HDR_SIZE - sizeof(u16); 1059 wpa_printf(MSG_DEBUG, "EAP-pwd: Fragmenting output, total " 1060 "length = %d", tot_len); 1061 } else { 1062 resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD, 1063 EAP_PWD_HDR_SIZE + len, 1064 EAP_CODE_RESPONSE, eap_get_id(reqData)); 1065 } 1066 if (resp == NULL) 1067 return NULL; 1068 1069 wpabuf_put_u8(resp, lm_exch); 1070 if (EAP_PWD_GET_LENGTH_BIT(lm_exch)) { 1071 wpabuf_put_be16(resp, tot_len); 1072 data->out_frag_pos += len; 1073 } 1074 buf = wpabuf_head_u8(data->outbuf); 1075 wpabuf_put_data(resp, buf, len); 1076 /* 1077 * if we're not fragmenting then there's no need to carry this around 1078 */ 1079 if (data->out_frag_pos == 0) { 1080 wpabuf_free(data->outbuf); 1081 data->outbuf = NULL; 1082 data->out_frag_pos = 0; 1083 if (data->state == SUCCESS_ON_FRAG_COMPLETION) { 1084 ret->methodState = METHOD_DONE; 1085 ret->decision = DECISION_UNCOND_SUCC; 1086 eap_pwd_state(data, SUCCESS); 1087 } 1088 } 1089 1090 return resp; 1091} 1092 1093 1094static Boolean eap_pwd_key_available(struct eap_sm *sm, void *priv) 1095{ 1096 struct eap_pwd_data *data = priv; 1097 return data->state == SUCCESS; 1098} 1099 1100 1101static u8 * eap_pwd_get_emsk(struct eap_sm *sm, void *priv, size_t *len) 1102{ 1103 struct eap_pwd_data *data = priv; 1104 u8 *key; 1105 1106 if (data->state != SUCCESS) 1107 return NULL; 1108 1109 if ((key = os_malloc(EAP_EMSK_LEN)) == NULL) 1110 return NULL; 1111 1112 os_memcpy(key, data->emsk, EAP_EMSK_LEN); 1113 *len = EAP_EMSK_LEN; 1114 1115 return key; 1116} 1117 1118 1119int eap_peer_pwd_register(void) 1120{ 1121 struct eap_method *eap; 1122 1123 eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, 1124 EAP_VENDOR_IETF, EAP_TYPE_PWD, "PWD"); 1125 if (eap == NULL) 1126 return -1; 1127 1128 eap->init = eap_pwd_init; 1129 eap->deinit = eap_pwd_deinit; 1130 eap->process = eap_pwd_process; 1131 eap->isKeyAvailable = eap_pwd_key_available; 1132 eap->getKey = eap_pwd_getkey; 1133 eap->getSessionId = eap_pwd_get_session_id; 1134 eap->get_emsk = eap_pwd_get_emsk; 1135 1136 return eap_peer_method_register(eap); 1137} 1138