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