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