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