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