1/* 2 * EAP peer method: EAP-EKE (RFC 6124) 3 * Copyright (c) 2013, Jouni Malinen <j@w1.fi> 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/random.h" 13#include "eap_peer/eap_i.h" 14#include "eap_common/eap_eke_common.h" 15 16struct eap_eke_data { 17 enum { 18 IDENTITY, COMMIT, CONFIRM, SUCCESS, FAILURE 19 } state; 20 u8 msk[EAP_MSK_LEN]; 21 u8 emsk[EAP_EMSK_LEN]; 22 u8 *peerid; 23 size_t peerid_len; 24 u8 *serverid; 25 size_t serverid_len; 26 u8 dh_priv[EAP_EKE_MAX_DH_LEN]; 27 struct eap_eke_session sess; 28 u8 nonce_p[EAP_EKE_MAX_NONCE_LEN]; 29 u8 nonce_s[EAP_EKE_MAX_NONCE_LEN]; 30 struct wpabuf *msgs; 31}; 32 33 34static const char * eap_eke_state_txt(int state) 35{ 36 switch (state) { 37 case IDENTITY: 38 return "IDENTITY"; 39 case COMMIT: 40 return "COMMIT"; 41 case CONFIRM: 42 return "CONFIRM"; 43 case SUCCESS: 44 return "SUCCESS"; 45 case FAILURE: 46 return "FAILURE"; 47 default: 48 return "?"; 49 } 50} 51 52 53static void eap_eke_state(struct eap_eke_data *data, int state) 54{ 55 wpa_printf(MSG_DEBUG, "EAP-EKE: %s -> %s", 56 eap_eke_state_txt(data->state), eap_eke_state_txt(state)); 57 data->state = state; 58} 59 60 61static void eap_eke_deinit(struct eap_sm *sm, void *priv); 62 63 64static void * eap_eke_init(struct eap_sm *sm) 65{ 66 struct eap_eke_data *data; 67 const u8 *identity, *password; 68 size_t identity_len, password_len; 69 70 password = eap_get_config_password(sm, &password_len); 71 if (!password) { 72 wpa_printf(MSG_INFO, "EAP-EKE: No password configured"); 73 return NULL; 74 } 75 76 data = os_zalloc(sizeof(*data)); 77 if (data == NULL) 78 return NULL; 79 eap_eke_state(data, IDENTITY); 80 81 identity = eap_get_config_identity(sm, &identity_len); 82 if (identity) { 83 data->peerid = os_malloc(identity_len); 84 if (data->peerid == NULL) { 85 eap_eke_deinit(sm, data); 86 return NULL; 87 } 88 os_memcpy(data->peerid, identity, identity_len); 89 data->peerid_len = identity_len; 90 } 91 92 return data; 93} 94 95 96static void eap_eke_deinit(struct eap_sm *sm, void *priv) 97{ 98 struct eap_eke_data *data = priv; 99 eap_eke_session_clean(&data->sess); 100 os_free(data->serverid); 101 os_free(data->peerid); 102 wpabuf_free(data->msgs); 103 os_free(data); 104} 105 106 107static struct wpabuf * eap_eke_build_msg(struct eap_eke_data *data, int id, 108 size_t length, u8 eke_exch) 109{ 110 struct wpabuf *msg; 111 size_t plen; 112 113 plen = 1 + length; 114 115 msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_EKE, plen, 116 EAP_CODE_RESPONSE, id); 117 if (msg == NULL) { 118 wpa_printf(MSG_ERROR, "EAP-EKE: Failed to allocate memory"); 119 return NULL; 120 } 121 122 wpabuf_put_u8(msg, eke_exch); 123 124 return msg; 125} 126 127 128static int eap_eke_supp_dhgroup(u8 dhgroup) 129{ 130 return dhgroup == EAP_EKE_DHGROUP_EKE_2 || 131 dhgroup == EAP_EKE_DHGROUP_EKE_5 || 132 dhgroup == EAP_EKE_DHGROUP_EKE_14 || 133 dhgroup == EAP_EKE_DHGROUP_EKE_15 || 134 dhgroup == EAP_EKE_DHGROUP_EKE_16; 135} 136 137 138static int eap_eke_supp_encr(u8 encr) 139{ 140 return encr == EAP_EKE_ENCR_AES128_CBC; 141} 142 143 144static int eap_eke_supp_prf(u8 prf) 145{ 146 return prf == EAP_EKE_PRF_HMAC_SHA1 || 147 prf == EAP_EKE_PRF_HMAC_SHA2_256; 148} 149 150 151static int eap_eke_supp_mac(u8 mac) 152{ 153 return mac == EAP_EKE_MAC_HMAC_SHA1 || 154 mac == EAP_EKE_MAC_HMAC_SHA2_256; 155} 156 157 158static struct wpabuf * eap_eke_build_fail(struct eap_eke_data *data, 159 struct eap_method_ret *ret, 160 const struct wpabuf *reqData, 161 u32 failure_code) 162{ 163 struct wpabuf *resp; 164 165 wpa_printf(MSG_DEBUG, "EAP-EKE: Sending EAP-EKE-Failure/Response - code=0x%x", 166 failure_code); 167 168 resp = eap_eke_build_msg(data, eap_get_id(reqData), 4, EAP_EKE_FAILURE); 169 if (resp) 170 wpabuf_put_be32(resp, failure_code); 171 172 os_memset(data->dh_priv, 0, sizeof(data->dh_priv)); 173 eap_eke_session_clean(&data->sess); 174 175 eap_eke_state(data, FAILURE); 176 ret->methodState = METHOD_DONE; 177 ret->decision = DECISION_FAIL; 178 ret->allowNotifications = FALSE; 179 180 return resp; 181} 182 183 184static struct wpabuf * eap_eke_process_id(struct eap_eke_data *data, 185 struct eap_method_ret *ret, 186 const struct wpabuf *reqData, 187 const u8 *payload, 188 size_t payload_len) 189{ 190 struct wpabuf *resp; 191 unsigned num_prop, i; 192 const u8 *pos, *end; 193 const u8 *prop = NULL; 194 u8 idtype; 195 196 if (data->state != IDENTITY) { 197 return eap_eke_build_fail(data, ret, reqData, 198 EAP_EKE_FAIL_PROTO_ERROR); 199 } 200 201 wpa_printf(MSG_DEBUG, "EAP-EKE: Received EAP-EKE-ID/Request"); 202 203 if (payload_len < 2 + 4) { 204 wpa_printf(MSG_DEBUG, "EAP-EKE: Too short ID/Request Data"); 205 return eap_eke_build_fail(data, ret, reqData, 206 EAP_EKE_FAIL_PROTO_ERROR); 207 } 208 209 pos = payload; 210 end = payload + payload_len; 211 212 num_prop = *pos++; 213 pos++; /* Ignore Reserved field */ 214 215 if (pos + num_prop * 4 > end) { 216 wpa_printf(MSG_DEBUG, "EAP-EKE: Too short ID/Request Data (num_prop=%u)", 217 num_prop); 218 return eap_eke_build_fail(data, ret, reqData, 219 EAP_EKE_FAIL_PROTO_ERROR); 220 } 221 222 for (i = 0; i < num_prop; i++) { 223 const u8 *tmp = pos; 224 225 wpa_printf(MSG_DEBUG, "EAP-EKE: Proposal #%u: dh=%u encr=%u prf=%u mac=%u", 226 i, pos[0], pos[1], pos[2], pos[3]); 227 pos += 4; 228 229 if (!eap_eke_supp_dhgroup(*tmp)) 230 continue; 231 tmp++; 232 if (!eap_eke_supp_encr(*tmp)) 233 continue; 234 tmp++; 235 if (!eap_eke_supp_prf(*tmp)) 236 continue; 237 tmp++; 238 if (!eap_eke_supp_mac(*tmp)) 239 continue; 240 241 prop = tmp - 3; 242 if (eap_eke_session_init(&data->sess, prop[0], prop[1], prop[2], 243 prop[3]) < 0) { 244 prop = NULL; 245 continue; 246 } 247 248 wpa_printf(MSG_DEBUG, "EAP-EKE: Selected proposal"); 249 break; 250 } 251 252 if (prop == NULL) { 253 wpa_printf(MSG_DEBUG, "EAP-EKE: No acceptable proposal found"); 254 return eap_eke_build_fail(data, ret, reqData, 255 EAP_EKE_FAIL_NO_PROPOSAL_CHOSEN); 256 } 257 258 pos += (num_prop - i - 1) * 4; 259 260 if (pos == end) { 261 wpa_printf(MSG_DEBUG, "EAP-EKE: Too short ID/Request Data to include IDType/Identity"); 262 return eap_eke_build_fail(data, ret, reqData, 263 EAP_EKE_FAIL_PROTO_ERROR); 264 } 265 266 idtype = *pos++; 267 wpa_printf(MSG_DEBUG, "EAP-EKE: Server IDType %u", idtype); 268 wpa_hexdump_ascii(MSG_DEBUG, "EAP-EKE: Server Identity", 269 pos, end - pos); 270 os_free(data->serverid); 271 data->serverid = os_malloc(end - pos); 272 if (data->serverid == NULL) { 273 return eap_eke_build_fail(data, ret, reqData, 274 EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 275 } 276 os_memcpy(data->serverid, pos, end - pos); 277 data->serverid_len = end - pos; 278 279 wpa_printf(MSG_DEBUG, "EAP-EKE: Sending EAP-EKE-ID/Response"); 280 281 resp = eap_eke_build_msg(data, eap_get_id(reqData), 282 2 + 4 + 1 + data->peerid_len, 283 EAP_EKE_ID); 284 if (resp == NULL) { 285 return eap_eke_build_fail(data, ret, reqData, 286 EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 287 } 288 289 wpabuf_put_u8(resp, 1); /* NumProposals */ 290 wpabuf_put_u8(resp, 0); /* Reserved */ 291 wpabuf_put_data(resp, prop, 4); /* Selected Proposal */ 292 wpabuf_put_u8(resp, EAP_EKE_ID_NAI); 293 if (data->peerid) 294 wpabuf_put_data(resp, data->peerid, data->peerid_len); 295 296 wpabuf_free(data->msgs); 297 data->msgs = wpabuf_alloc(wpabuf_len(reqData) + wpabuf_len(resp)); 298 if (data->msgs == NULL) { 299 wpabuf_free(resp); 300 return eap_eke_build_fail(data, ret, reqData, 301 EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 302 } 303 wpabuf_put_buf(data->msgs, reqData); 304 wpabuf_put_buf(data->msgs, resp); 305 306 eap_eke_state(data, COMMIT); 307 308 return resp; 309} 310 311 312static struct wpabuf * eap_eke_process_commit(struct eap_sm *sm, 313 struct eap_eke_data *data, 314 struct eap_method_ret *ret, 315 const struct wpabuf *reqData, 316 const u8 *payload, 317 size_t payload_len) 318{ 319 struct wpabuf *resp; 320 const u8 *pos, *end, *dhcomp; 321 size_t prot_len; 322 u8 *rpos; 323 u8 key[EAP_EKE_MAX_KEY_LEN]; 324 u8 pub[EAP_EKE_MAX_DH_LEN]; 325 const u8 *password; 326 size_t password_len; 327 328 if (data->state != COMMIT) { 329 wpa_printf(MSG_DEBUG, "EAP-EKE: EAP-EKE-Commit/Request received in unexpected state (%d)", data->state); 330 return eap_eke_build_fail(data, ret, reqData, 331 EAP_EKE_FAIL_PROTO_ERROR); 332 } 333 334 wpa_printf(MSG_DEBUG, "EAP-EKE: Received EAP-EKE-Commit/Request"); 335 336 password = eap_get_config_password(sm, &password_len); 337 if (password == NULL) { 338 wpa_printf(MSG_INFO, "EAP-EKE: No password configured!"); 339 return eap_eke_build_fail(data, ret, reqData, 340 EAP_EKE_FAIL_PASSWD_NOT_FOUND); 341 } 342 343 pos = payload; 344 end = payload + payload_len; 345 346 if (pos + data->sess.dhcomp_len > end) { 347 wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Commit"); 348 return eap_eke_build_fail(data, ret, reqData, 349 EAP_EKE_FAIL_PROTO_ERROR); 350 } 351 352 wpa_hexdump(MSG_DEBUG, "EAP-EKE: DHComponent_S", 353 pos, data->sess.dhcomp_len); 354 dhcomp = pos; 355 pos += data->sess.dhcomp_len; 356 wpa_hexdump(MSG_DEBUG, "EAP-EKE: CBValue", pos, end - pos); 357 358 /* 359 * temp = prf(0+, password) 360 * key = prf+(temp, ID_S | ID_P) 361 */ 362 if (eap_eke_derive_key(&data->sess, password, password_len, 363 data->serverid, data->serverid_len, 364 data->peerid, data->peerid_len, key) < 0) { 365 wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive key"); 366 return eap_eke_build_fail(data, ret, reqData, 367 EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 368 } 369 370 /* 371 * y_p = g ^ x_p (mod p) 372 * x_p = random number 2 .. p-1 373 */ 374 if (eap_eke_dh_init(data->sess.dhgroup, data->dh_priv, pub) < 0) { 375 wpa_printf(MSG_INFO, "EAP-EKE: Failed to initialize DH"); 376 os_memset(key, 0, sizeof(key)); 377 return eap_eke_build_fail(data, ret, reqData, 378 EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 379 } 380 381 if (eap_eke_shared_secret(&data->sess, key, data->dh_priv, dhcomp) < 0) 382 { 383 wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive shared secret"); 384 os_memset(key, 0, sizeof(key)); 385 return eap_eke_build_fail(data, ret, reqData, 386 EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 387 } 388 389 if (eap_eke_derive_ke_ki(&data->sess, 390 data->serverid, data->serverid_len, 391 data->peerid, data->peerid_len) < 0) { 392 wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive Ke/Ki"); 393 os_memset(key, 0, sizeof(key)); 394 return eap_eke_build_fail(data, ret, reqData, 395 EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 396 } 397 398 wpa_printf(MSG_DEBUG, "EAP-EKE: Sending EAP-EKE-Commit/Response"); 399 400 resp = eap_eke_build_msg(data, eap_get_id(reqData), 401 data->sess.dhcomp_len + data->sess.pnonce_len, 402 EAP_EKE_COMMIT); 403 if (resp == NULL) { 404 os_memset(key, 0, sizeof(key)); 405 return eap_eke_build_fail(data, ret, reqData, 406 EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 407 } 408 409 /* DHComponent_P = Encr(key, y_p) */ 410 rpos = wpabuf_put(resp, data->sess.dhcomp_len); 411 if (eap_eke_dhcomp(&data->sess, key, pub, rpos) < 0) { 412 wpa_printf(MSG_INFO, "EAP-EKE: Failed to build DHComponent_S"); 413 os_memset(key, 0, sizeof(key)); 414 return eap_eke_build_fail(data, ret, reqData, 415 EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 416 } 417 os_memset(key, 0, sizeof(key)); 418 419 wpa_hexdump(MSG_DEBUG, "EAP-EKE: DHComponent_P", 420 rpos, data->sess.dhcomp_len); 421 422 if (random_get_bytes(data->nonce_p, data->sess.nonce_len)) { 423 wpabuf_free(resp); 424 return eap_eke_build_fail(data, ret, reqData, 425 EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 426 } 427 wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Nonce_P", 428 data->nonce_p, data->sess.nonce_len); 429 prot_len = wpabuf_tailroom(resp); 430 if (eap_eke_prot(&data->sess, data->nonce_p, data->sess.nonce_len, 431 wpabuf_put(resp, 0), &prot_len) < 0) { 432 wpabuf_free(resp); 433 return eap_eke_build_fail(data, ret, reqData, 434 EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 435 } 436 wpa_hexdump(MSG_DEBUG, "EAP-EKE: PNonce_P", 437 wpabuf_put(resp, 0), prot_len); 438 wpabuf_put(resp, prot_len); 439 440 /* TODO: CBValue */ 441 442 if (wpabuf_resize(&data->msgs, wpabuf_len(reqData) + wpabuf_len(resp)) 443 < 0) { 444 wpabuf_free(resp); 445 return eap_eke_build_fail(data, ret, reqData, 446 EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 447 } 448 wpabuf_put_buf(data->msgs, reqData); 449 wpabuf_put_buf(data->msgs, resp); 450 451 eap_eke_state(data, CONFIRM); 452 453 return resp; 454} 455 456 457static struct wpabuf * eap_eke_process_confirm(struct eap_eke_data *data, 458 struct eap_method_ret *ret, 459 const struct wpabuf *reqData, 460 const u8 *payload, 461 size_t payload_len) 462{ 463 struct wpabuf *resp; 464 const u8 *pos, *end; 465 size_t prot_len; 466 u8 nonces[2 * EAP_EKE_MAX_NONCE_LEN]; 467 u8 auth_s[EAP_EKE_MAX_HASH_LEN]; 468 size_t decrypt_len; 469 u8 *auth; 470 471 if (data->state != CONFIRM) { 472 wpa_printf(MSG_DEBUG, "EAP-EKE: EAP-EKE-Confirm/Request received in unexpected state (%d)", 473 data->state); 474 return eap_eke_build_fail(data, ret, reqData, 475 EAP_EKE_FAIL_PROTO_ERROR); 476 } 477 478 wpa_printf(MSG_DEBUG, "EAP-EKE: Received EAP-EKE-Confirm/Request"); 479 480 pos = payload; 481 end = payload + payload_len; 482 483 if (pos + data->sess.pnonce_ps_len + data->sess.prf_len > end) { 484 wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Commit"); 485 return eap_eke_build_fail(data, ret, reqData, 486 EAP_EKE_FAIL_PROTO_ERROR); 487 } 488 489 decrypt_len = sizeof(nonces); 490 if (eap_eke_decrypt_prot(&data->sess, pos, data->sess.pnonce_ps_len, 491 nonces, &decrypt_len) < 0) { 492 wpa_printf(MSG_INFO, "EAP-EKE: Failed to decrypt PNonce_PS"); 493 return eap_eke_build_fail(data, ret, reqData, 494 EAP_EKE_FAIL_AUTHENTICATION_FAIL); 495 } 496 if (decrypt_len != (size_t) 2 * data->sess.nonce_len) { 497 wpa_printf(MSG_INFO, "EAP-EKE: PNonce_PS protected data length does not match length of Nonce_P and Nonce_S"); 498 return eap_eke_build_fail(data, ret, reqData, 499 EAP_EKE_FAIL_AUTHENTICATION_FAIL); 500 } 501 wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Received Nonce_P | Nonce_S", 502 nonces, 2 * data->sess.nonce_len); 503 if (os_memcmp(data->nonce_p, nonces, data->sess.nonce_len) != 0) { 504 wpa_printf(MSG_INFO, "EAP-EKE: Received Nonce_P does not match trnsmitted Nonce_P"); 505 return eap_eke_build_fail(data, ret, reqData, 506 EAP_EKE_FAIL_AUTHENTICATION_FAIL); 507 } 508 509 os_memcpy(data->nonce_s, nonces + data->sess.nonce_len, 510 data->sess.nonce_len); 511 wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Nonce_S", 512 data->nonce_s, data->sess.nonce_len); 513 514 if (eap_eke_derive_ka(&data->sess, data->serverid, data->serverid_len, 515 data->peerid, data->peerid_len, 516 data->nonce_p, data->nonce_s) < 0) { 517 return eap_eke_build_fail(data, ret, reqData, 518 EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 519 } 520 521 if (eap_eke_auth(&data->sess, "EAP-EKE server", data->msgs, auth_s) < 0) 522 { 523 return eap_eke_build_fail(data, ret, reqData, 524 EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 525 } 526 wpa_hexdump(MSG_DEBUG, "EAP-EKE: Auth_S", auth_s, data->sess.prf_len); 527 if (os_memcmp(auth_s, pos + data->sess.pnonce_ps_len, 528 data->sess.prf_len) != 0) { 529 wpa_printf(MSG_INFO, "EAP-EKE: Auth_S does not match"); 530 return eap_eke_build_fail(data, ret, reqData, 531 EAP_EKE_FAIL_AUTHENTICATION_FAIL); 532 } 533 534 wpa_printf(MSG_DEBUG, "EAP-EKE: Sending EAP-EKE-Confirm/Response"); 535 536 resp = eap_eke_build_msg(data, eap_get_id(reqData), 537 data->sess.pnonce_len + data->sess.prf_len, 538 EAP_EKE_CONFIRM); 539 if (resp == NULL) { 540 return eap_eke_build_fail(data, ret, reqData, 541 EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 542 } 543 544 prot_len = wpabuf_tailroom(resp); 545 if (eap_eke_prot(&data->sess, data->nonce_s, data->sess.nonce_len, 546 wpabuf_put(resp, 0), &prot_len) < 0) { 547 wpabuf_free(resp); 548 return eap_eke_build_fail(data, ret, reqData, 549 EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 550 } 551 wpabuf_put(resp, prot_len); 552 553 auth = wpabuf_put(resp, data->sess.prf_len); 554 if (eap_eke_auth(&data->sess, "EAP-EKE peer", data->msgs, auth) < 0) { 555 wpabuf_free(resp); 556 return eap_eke_build_fail(data, ret, reqData, 557 EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 558 } 559 wpa_hexdump(MSG_DEBUG, "EAP-EKE: Auth_P", auth, data->sess.prf_len); 560 561 if (eap_eke_derive_msk(&data->sess, data->serverid, data->serverid_len, 562 data->peerid, data->peerid_len, 563 data->nonce_s, data->nonce_p, 564 data->msk, data->emsk) < 0) { 565 wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive MSK/EMSK"); 566 wpabuf_free(resp); 567 return eap_eke_build_fail(data, ret, reqData, 568 EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 569 } 570 571 os_memset(data->dh_priv, 0, sizeof(data->dh_priv)); 572 eap_eke_session_clean(&data->sess); 573 574 eap_eke_state(data, SUCCESS); 575 ret->methodState = METHOD_MAY_CONT; 576 ret->decision = DECISION_COND_SUCC; 577 ret->allowNotifications = FALSE; 578 579 return resp; 580} 581 582 583static struct wpabuf * eap_eke_process_failure(struct eap_eke_data *data, 584 struct eap_method_ret *ret, 585 const struct wpabuf *reqData, 586 const u8 *payload, 587 size_t payload_len) 588{ 589 wpa_printf(MSG_DEBUG, "EAP-EKE: Received EAP-EKE-Failure/Request"); 590 591 if (payload_len < 4) { 592 wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Failure"); 593 } else { 594 u32 code; 595 code = WPA_GET_BE32(payload); 596 wpa_printf(MSG_INFO, "EAP-EKE: Failure-Code 0x%x", code); 597 } 598 599 return eap_eke_build_fail(data, ret, reqData, EAP_EKE_FAIL_NO_ERROR); 600} 601 602 603static struct wpabuf * eap_eke_process(struct eap_sm *sm, void *priv, 604 struct eap_method_ret *ret, 605 const struct wpabuf *reqData) 606{ 607 struct eap_eke_data *data = priv; 608 struct wpabuf *resp; 609 const u8 *pos, *end; 610 size_t len; 611 u8 eke_exch; 612 613 pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_EKE, reqData, &len); 614 if (pos == NULL || len < 1) { 615 ret->ignore = TRUE; 616 return NULL; 617 } 618 619 end = pos + len; 620 eke_exch = *pos++; 621 622 wpa_printf(MSG_DEBUG, "EAP-EKE: Received frame: exch %d", eke_exch); 623 wpa_hexdump(MSG_DEBUG, "EAP-EKE: Received Data", pos, end - pos); 624 625 ret->ignore = FALSE; 626 ret->methodState = METHOD_MAY_CONT; 627 ret->decision = DECISION_FAIL; 628 ret->allowNotifications = TRUE; 629 630 switch (eke_exch) { 631 case EAP_EKE_ID: 632 resp = eap_eke_process_id(data, ret, reqData, pos, end - pos); 633 break; 634 case EAP_EKE_COMMIT: 635 resp = eap_eke_process_commit(sm, data, ret, reqData, 636 pos, end - pos); 637 break; 638 case EAP_EKE_CONFIRM: 639 resp = eap_eke_process_confirm(data, ret, reqData, 640 pos, end - pos); 641 break; 642 case EAP_EKE_FAILURE: 643 resp = eap_eke_process_failure(data, ret, reqData, 644 pos, end - pos); 645 break; 646 default: 647 wpa_printf(MSG_DEBUG, "EAP-EKE: Ignoring message with unknown EKE-Exch %d", eke_exch); 648 ret->ignore = TRUE; 649 return NULL; 650 } 651 652 if (ret->methodState == METHOD_DONE) 653 ret->allowNotifications = FALSE; 654 655 return resp; 656} 657 658 659static Boolean eap_eke_isKeyAvailable(struct eap_sm *sm, void *priv) 660{ 661 struct eap_eke_data *data = priv; 662 return data->state == SUCCESS; 663} 664 665 666static u8 * eap_eke_getKey(struct eap_sm *sm, void *priv, size_t *len) 667{ 668 struct eap_eke_data *data = priv; 669 u8 *key; 670 671 if (data->state != SUCCESS) 672 return NULL; 673 674 key = os_malloc(EAP_MSK_LEN); 675 if (key == NULL) 676 return NULL; 677 os_memcpy(key, data->msk, EAP_MSK_LEN); 678 *len = EAP_MSK_LEN; 679 680 return key; 681} 682 683 684static u8 * eap_eke_get_emsk(struct eap_sm *sm, void *priv, size_t *len) 685{ 686 struct eap_eke_data *data = priv; 687 u8 *key; 688 689 if (data->state != SUCCESS) 690 return NULL; 691 692 key = os_malloc(EAP_EMSK_LEN); 693 if (key == NULL) 694 return NULL; 695 os_memcpy(key, data->emsk, EAP_EMSK_LEN); 696 *len = EAP_EMSK_LEN; 697 698 return key; 699} 700 701 702int eap_peer_eke_register(void) 703{ 704 struct eap_method *eap; 705 int ret; 706 707 eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, 708 EAP_VENDOR_IETF, EAP_TYPE_EKE, "EKE"); 709 if (eap == NULL) 710 return -1; 711 712 eap->init = eap_eke_init; 713 eap->deinit = eap_eke_deinit; 714 eap->process = eap_eke_process; 715 eap->isKeyAvailable = eap_eke_isKeyAvailable; 716 eap->getKey = eap_eke_getKey; 717 eap->get_emsk = eap_eke_get_emsk; 718 719 ret = eap_peer_method_register(eap); 720 if (ret) 721 eap_peer_method_free(eap); 722 return ret; 723} 724