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