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