eap_gpsk.c revision 0c08fdcf5231617f2340cb18e45769a8ed3a1dc4
1/* 2 * EAP peer method: EAP-GPSK (RFC 5433) 3 * Copyright (c) 2006-2014, 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_gpsk_common.h" 15 16struct eap_gpsk_data { 17 enum { GPSK_1, GPSK_3, SUCCESS, FAILURE } state; 18 u8 rand_server[EAP_GPSK_RAND_LEN]; 19 u8 rand_peer[EAP_GPSK_RAND_LEN]; 20 u8 msk[EAP_MSK_LEN]; 21 u8 emsk[EAP_EMSK_LEN]; 22 u8 sk[EAP_GPSK_MAX_SK_LEN]; 23 size_t sk_len; 24 u8 pk[EAP_GPSK_MAX_PK_LEN]; 25 size_t pk_len; 26 u8 session_id[128]; 27 size_t id_len; 28 u8 *id_peer; 29 size_t id_peer_len; 30 u8 *id_server; 31 size_t id_server_len; 32 int vendor; /* CSuite/Specifier */ 33 int specifier; /* CSuite/Specifier */ 34 u8 *psk; 35 size_t psk_len; 36 u16 forced_cipher; /* force cipher or 0 to allow all supported */ 37}; 38 39 40static struct wpabuf * eap_gpsk_send_gpsk_2(struct eap_gpsk_data *data, 41 u8 identifier, 42 const u8 *csuite_list, 43 size_t csuite_list_len); 44static struct wpabuf * eap_gpsk_send_gpsk_4(struct eap_gpsk_data *data, 45 u8 identifier); 46 47 48#ifndef CONFIG_NO_STDOUT_DEBUG 49static const char * eap_gpsk_state_txt(int state) 50{ 51 switch (state) { 52 case GPSK_1: 53 return "GPSK-1"; 54 case GPSK_3: 55 return "GPSK-3"; 56 case SUCCESS: 57 return "SUCCESS"; 58 case FAILURE: 59 return "FAILURE"; 60 default: 61 return "?"; 62 } 63} 64#endif /* CONFIG_NO_STDOUT_DEBUG */ 65 66 67static void eap_gpsk_state(struct eap_gpsk_data *data, int state) 68{ 69 wpa_printf(MSG_DEBUG, "EAP-GPSK: %s -> %s", 70 eap_gpsk_state_txt(data->state), 71 eap_gpsk_state_txt(state)); 72 data->state = state; 73} 74 75 76static void eap_gpsk_deinit(struct eap_sm *sm, void *priv); 77 78 79static void * eap_gpsk_init(struct eap_sm *sm) 80{ 81 struct eap_gpsk_data *data; 82 const u8 *identity, *password; 83 size_t identity_len, password_len; 84 const char *phase1; 85 86 password = eap_get_config_password(sm, &password_len); 87 if (password == NULL) { 88 wpa_printf(MSG_INFO, "EAP-GPSK: No key (password) configured"); 89 return NULL; 90 } 91 92 data = os_zalloc(sizeof(*data)); 93 if (data == NULL) 94 return NULL; 95 data->state = GPSK_1; 96 97 identity = eap_get_config_identity(sm, &identity_len); 98 if (identity) { 99 data->id_peer = os_malloc(identity_len); 100 if (data->id_peer == NULL) { 101 eap_gpsk_deinit(sm, data); 102 return NULL; 103 } 104 os_memcpy(data->id_peer, identity, identity_len); 105 data->id_peer_len = identity_len; 106 } 107 108 phase1 = eap_get_config_phase1(sm); 109 if (phase1) { 110 const char *pos; 111 112 pos = os_strstr(phase1, "cipher="); 113 if (pos) { 114 data->forced_cipher = atoi(pos + 7); 115 wpa_printf(MSG_DEBUG, "EAP-GPSK: Forced cipher %u", 116 data->forced_cipher); 117 } 118 } 119 120 data->psk = os_malloc(password_len); 121 if (data->psk == NULL) { 122 eap_gpsk_deinit(sm, data); 123 return NULL; 124 } 125 os_memcpy(data->psk, password, password_len); 126 data->psk_len = password_len; 127 128 return data; 129} 130 131 132static void eap_gpsk_deinit(struct eap_sm *sm, void *priv) 133{ 134 struct eap_gpsk_data *data = priv; 135 os_free(data->id_server); 136 os_free(data->id_peer); 137 os_free(data->psk); 138 os_free(data); 139} 140 141 142static const u8 * eap_gpsk_process_id_server(struct eap_gpsk_data *data, 143 const u8 *pos, const u8 *end) 144{ 145 u16 alen; 146 147 if (end - pos < 2) { 148 wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short GPSK-1 packet"); 149 return NULL; 150 } 151 alen = WPA_GET_BE16(pos); 152 pos += 2; 153 if (end - pos < alen) { 154 wpa_printf(MSG_DEBUG, "EAP-GPSK: ID_Server overflow"); 155 return NULL; 156 } 157 os_free(data->id_server); 158 data->id_server = os_malloc(alen); 159 if (data->id_server == NULL) { 160 wpa_printf(MSG_DEBUG, "EAP-GPSK: No memory for ID_Server"); 161 return NULL; 162 } 163 os_memcpy(data->id_server, pos, alen); 164 data->id_server_len = alen; 165 wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Server", 166 data->id_server, data->id_server_len); 167 pos += alen; 168 169 return pos; 170} 171 172 173static const u8 * eap_gpsk_process_rand_server(struct eap_gpsk_data *data, 174 const u8 *pos, const u8 *end) 175{ 176 if (pos == NULL) 177 return NULL; 178 179 if (end - pos < EAP_GPSK_RAND_LEN) { 180 wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Server overflow"); 181 return NULL; 182 } 183 os_memcpy(data->rand_server, pos, EAP_GPSK_RAND_LEN); 184 wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server", 185 data->rand_server, EAP_GPSK_RAND_LEN); 186 pos += EAP_GPSK_RAND_LEN; 187 188 return pos; 189} 190 191 192static int eap_gpsk_select_csuite(struct eap_sm *sm, 193 struct eap_gpsk_data *data, 194 const u8 *csuite_list, 195 size_t csuite_list_len) 196{ 197 struct eap_gpsk_csuite *csuite; 198 int i, count; 199 200 count = csuite_list_len / sizeof(struct eap_gpsk_csuite); 201 data->vendor = EAP_GPSK_VENDOR_IETF; 202 data->specifier = EAP_GPSK_CIPHER_RESERVED; 203 csuite = (struct eap_gpsk_csuite *) csuite_list; 204 for (i = 0; i < count; i++) { 205 int vendor, specifier; 206 vendor = WPA_GET_BE32(csuite->vendor); 207 specifier = WPA_GET_BE16(csuite->specifier); 208 wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite[%d]: %d:%d", 209 i, vendor, specifier); 210 if (data->vendor == EAP_GPSK_VENDOR_IETF && 211 data->specifier == EAP_GPSK_CIPHER_RESERVED && 212 eap_gpsk_supported_ciphersuite(vendor, specifier) && 213 (!data->forced_cipher || data->forced_cipher == specifier)) 214 { 215 data->vendor = vendor; 216 data->specifier = specifier; 217 } 218 csuite++; 219 } 220 if (data->vendor == EAP_GPSK_VENDOR_IETF && 221 data->specifier == EAP_GPSK_CIPHER_RESERVED) { 222 wpa_msg(sm->msg_ctx, MSG_INFO, "EAP-GPSK: No supported " 223 "ciphersuite found"); 224 return -1; 225 } 226 wpa_printf(MSG_DEBUG, "EAP-GPSK: Selected ciphersuite %d:%d", 227 data->vendor, data->specifier); 228 229 return 0; 230} 231 232 233static const u8 * eap_gpsk_process_csuite_list(struct eap_sm *sm, 234 struct eap_gpsk_data *data, 235 const u8 **list, 236 size_t *list_len, 237 const u8 *pos, const u8 *end) 238{ 239 size_t len; 240 241 if (pos == NULL) 242 return NULL; 243 244 if (end - pos < 2) { 245 wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short GPSK-1 packet"); 246 return NULL; 247 } 248 len = WPA_GET_BE16(pos); 249 pos += 2; 250 if (len > (size_t) (end - pos)) { 251 wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_List overflow"); 252 return NULL; 253 } 254 if (len == 0 || (len % sizeof(struct eap_gpsk_csuite))) { 255 wpa_printf(MSG_DEBUG, "EAP-GPSK: Invalid CSuite_List len %lu", 256 (unsigned long) len); 257 return NULL; 258 } 259 260 if (eap_gpsk_select_csuite(sm, data, pos, len) < 0) 261 return NULL; 262 263 *list = pos; 264 *list_len = len; 265 pos += len; 266 267 return pos; 268} 269 270 271static struct wpabuf * eap_gpsk_process_gpsk_1(struct eap_sm *sm, 272 struct eap_gpsk_data *data, 273 struct eap_method_ret *ret, 274 const struct wpabuf *reqData, 275 const u8 *payload, 276 size_t payload_len) 277{ 278 size_t csuite_list_len; 279 const u8 *csuite_list, *pos, *end; 280 struct wpabuf *resp; 281 282 if (data->state != GPSK_1) { 283 ret->ignore = TRUE; 284 return NULL; 285 } 286 287 wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Request/GPSK-1"); 288 289 end = payload + payload_len; 290 291 pos = eap_gpsk_process_id_server(data, payload, end); 292 pos = eap_gpsk_process_rand_server(data, pos, end); 293 pos = eap_gpsk_process_csuite_list(sm, data, &csuite_list, 294 &csuite_list_len, pos, end); 295 if (pos == NULL) { 296 ret->methodState = METHOD_DONE; 297 eap_gpsk_state(data, FAILURE); 298 return NULL; 299 } 300 301 resp = eap_gpsk_send_gpsk_2(data, eap_get_id(reqData), 302 csuite_list, csuite_list_len); 303 if (resp == NULL) 304 return NULL; 305 306 eap_gpsk_state(data, GPSK_3); 307 308 return resp; 309} 310 311 312static struct wpabuf * eap_gpsk_send_gpsk_2(struct eap_gpsk_data *data, 313 u8 identifier, 314 const u8 *csuite_list, 315 size_t csuite_list_len) 316{ 317 struct wpabuf *resp; 318 size_t len, miclen; 319 u8 *rpos, *start; 320 struct eap_gpsk_csuite *csuite; 321 322 wpa_printf(MSG_DEBUG, "EAP-GPSK: Sending Response/GPSK-2"); 323 324 miclen = eap_gpsk_mic_len(data->vendor, data->specifier); 325 len = 1 + 2 + data->id_peer_len + 2 + data->id_server_len + 326 2 * EAP_GPSK_RAND_LEN + 2 + csuite_list_len + 327 sizeof(struct eap_gpsk_csuite) + 2 + miclen; 328 329 resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, len, 330 EAP_CODE_RESPONSE, identifier); 331 if (resp == NULL) 332 return NULL; 333 334 wpabuf_put_u8(resp, EAP_GPSK_OPCODE_GPSK_2); 335 start = wpabuf_put(resp, 0); 336 337 wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Peer", 338 data->id_peer, data->id_peer_len); 339 wpabuf_put_be16(resp, data->id_peer_len); 340 wpabuf_put_data(resp, data->id_peer, data->id_peer_len); 341 342 wpabuf_put_be16(resp, data->id_server_len); 343 wpabuf_put_data(resp, data->id_server, data->id_server_len); 344 345 if (random_get_bytes(data->rand_peer, EAP_GPSK_RAND_LEN)) { 346 wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to get random data " 347 "for RAND_Peer"); 348 eap_gpsk_state(data, FAILURE); 349 wpabuf_free(resp); 350 return NULL; 351 } 352 wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Peer", 353 data->rand_peer, EAP_GPSK_RAND_LEN); 354 wpabuf_put_data(resp, data->rand_peer, EAP_GPSK_RAND_LEN); 355 wpabuf_put_data(resp, data->rand_server, EAP_GPSK_RAND_LEN); 356 357 wpabuf_put_be16(resp, csuite_list_len); 358 wpabuf_put_data(resp, csuite_list, csuite_list_len); 359 360 csuite = wpabuf_put(resp, sizeof(*csuite)); 361 WPA_PUT_BE32(csuite->vendor, data->vendor); 362 WPA_PUT_BE16(csuite->specifier, data->specifier); 363 364 if (eap_gpsk_derive_keys(data->psk, data->psk_len, 365 data->vendor, data->specifier, 366 data->rand_peer, data->rand_server, 367 data->id_peer, data->id_peer_len, 368 data->id_server, data->id_server_len, 369 data->msk, data->emsk, 370 data->sk, &data->sk_len, 371 data->pk, &data->pk_len) < 0) { 372 wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to derive keys"); 373 eap_gpsk_state(data, FAILURE); 374 wpabuf_free(resp); 375 return NULL; 376 } 377 378 if (eap_gpsk_derive_session_id(data->psk, data->psk_len, 379 data->vendor, data->specifier, 380 data->rand_peer, data->rand_server, 381 data->id_peer, data->id_peer_len, 382 data->id_server, data->id_server_len, 383 EAP_TYPE_GPSK, 384 data->session_id, &data->id_len) < 0) { 385 wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to derive Session-Id"); 386 eap_gpsk_state(data, FAILURE); 387 wpabuf_free(resp); 388 return NULL; 389 } 390 wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Derived Session-Id", 391 data->session_id, data->id_len); 392 393 /* No PD_Payload_1 */ 394 wpabuf_put_be16(resp, 0); 395 396 rpos = wpabuf_put(resp, miclen); 397 if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor, 398 data->specifier, start, rpos - start, rpos) < 399 0) { 400 eap_gpsk_state(data, FAILURE); 401 wpabuf_free(resp); 402 return NULL; 403 } 404 405 return resp; 406} 407 408 409static const u8 * eap_gpsk_validate_rand(struct eap_gpsk_data *data, 410 const u8 *pos, const u8 *end) 411{ 412 if (end - pos < EAP_GPSK_RAND_LEN) { 413 wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for " 414 "RAND_Peer"); 415 return NULL; 416 } 417 if (os_memcmp(pos, data->rand_peer, EAP_GPSK_RAND_LEN) != 0) { 418 wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Peer in GPSK-2 and " 419 "GPSK-3 did not match"); 420 wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Peer in GPSK-2", 421 data->rand_peer, EAP_GPSK_RAND_LEN); 422 wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Peer in GPSK-3", 423 pos, EAP_GPSK_RAND_LEN); 424 return NULL; 425 } 426 pos += EAP_GPSK_RAND_LEN; 427 428 if (end - pos < EAP_GPSK_RAND_LEN) { 429 wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for " 430 "RAND_Server"); 431 return NULL; 432 } 433 if (os_memcmp(pos, data->rand_server, EAP_GPSK_RAND_LEN) != 0) { 434 wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1 and " 435 "GPSK-3 did not match"); 436 wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1", 437 data->rand_server, EAP_GPSK_RAND_LEN); 438 wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-3", 439 pos, EAP_GPSK_RAND_LEN); 440 return NULL; 441 } 442 pos += EAP_GPSK_RAND_LEN; 443 444 return pos; 445} 446 447 448static const u8 * eap_gpsk_validate_id_server(struct eap_gpsk_data *data, 449 const u8 *pos, const u8 *end) 450{ 451 size_t len; 452 453 if (pos == NULL) 454 return NULL; 455 456 if (end - pos < (int) 2) { 457 wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for " 458 "length(ID_Server)"); 459 return NULL; 460 } 461 462 len = WPA_GET_BE16(pos); 463 pos += 2; 464 465 if (end - pos < (int) len) { 466 wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for " 467 "ID_Server"); 468 return NULL; 469 } 470 471 if (len != data->id_server_len || 472 os_memcmp(pos, data->id_server, len) != 0) { 473 wpa_printf(MSG_INFO, "EAP-GPSK: ID_Server did not match with " 474 "the one used in GPSK-1"); 475 wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Server in GPSK-1", 476 data->id_server, data->id_server_len); 477 wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Server in GPSK-3", 478 pos, len); 479 return NULL; 480 } 481 482 pos += len; 483 484 return pos; 485} 486 487 488static const u8 * eap_gpsk_validate_csuite(struct eap_gpsk_data *data, 489 const u8 *pos, const u8 *end) 490{ 491 int vendor, specifier; 492 const struct eap_gpsk_csuite *csuite; 493 494 if (pos == NULL) 495 return NULL; 496 497 if (end - pos < (int) sizeof(*csuite)) { 498 wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for " 499 "CSuite_Sel"); 500 return NULL; 501 } 502 csuite = (const struct eap_gpsk_csuite *) pos; 503 vendor = WPA_GET_BE32(csuite->vendor); 504 specifier = WPA_GET_BE16(csuite->specifier); 505 pos += sizeof(*csuite); 506 if (vendor != data->vendor || specifier != data->specifier) { 507 wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_Sel (%d:%d) does not " 508 "match with the one sent in GPSK-2 (%d:%d)", 509 vendor, specifier, data->vendor, data->specifier); 510 return NULL; 511 } 512 513 return pos; 514} 515 516 517static const u8 * eap_gpsk_validate_pd_payload_2(struct eap_gpsk_data *data, 518 const u8 *pos, const u8 *end) 519{ 520 u16 alen; 521 522 if (pos == NULL) 523 return NULL; 524 525 if (end - pos < 2) { 526 wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for " 527 "PD_Payload_2 length"); 528 return NULL; 529 } 530 alen = WPA_GET_BE16(pos); 531 pos += 2; 532 if (end - pos < alen) { 533 wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for " 534 "%d-octet PD_Payload_2", alen); 535 return NULL; 536 } 537 wpa_hexdump(MSG_DEBUG, "EAP-GPSK: PD_Payload_2", pos, alen); 538 pos += alen; 539 540 return pos; 541} 542 543 544static const u8 * eap_gpsk_validate_gpsk_3_mic(struct eap_gpsk_data *data, 545 const u8 *payload, 546 const u8 *pos, const u8 *end) 547{ 548 size_t miclen; 549 u8 mic[EAP_GPSK_MAX_MIC_LEN]; 550 551 if (pos == NULL) 552 return NULL; 553 554 miclen = eap_gpsk_mic_len(data->vendor, data->specifier); 555 if (end - pos < (int) miclen) { 556 wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for MIC " 557 "(left=%lu miclen=%lu)", 558 (unsigned long) (end - pos), 559 (unsigned long) miclen); 560 return NULL; 561 } 562 if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor, 563 data->specifier, payload, pos - payload, mic) 564 < 0) { 565 wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to compute MIC"); 566 return NULL; 567 } 568 if (os_memcmp(mic, pos, miclen) != 0) { 569 wpa_printf(MSG_INFO, "EAP-GPSK: Incorrect MIC in GPSK-3"); 570 wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Received MIC", pos, miclen); 571 wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Computed MIC", mic, miclen); 572 return NULL; 573 } 574 pos += miclen; 575 576 return pos; 577} 578 579 580static struct wpabuf * eap_gpsk_process_gpsk_3(struct eap_sm *sm, 581 struct eap_gpsk_data *data, 582 struct eap_method_ret *ret, 583 const struct wpabuf *reqData, 584 const u8 *payload, 585 size_t payload_len) 586{ 587 struct wpabuf *resp; 588 const u8 *pos, *end; 589 590 if (data->state != GPSK_3) { 591 ret->ignore = TRUE; 592 return NULL; 593 } 594 595 wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Request/GPSK-3"); 596 597 end = payload + payload_len; 598 599 pos = eap_gpsk_validate_rand(data, payload, end); 600 pos = eap_gpsk_validate_id_server(data, pos, end); 601 pos = eap_gpsk_validate_csuite(data, pos, end); 602 pos = eap_gpsk_validate_pd_payload_2(data, pos, end); 603 pos = eap_gpsk_validate_gpsk_3_mic(data, payload, pos, end); 604 605 if (pos == NULL) { 606 eap_gpsk_state(data, FAILURE); 607 return NULL; 608 } 609 if (pos != end) { 610 wpa_printf(MSG_DEBUG, "EAP-GPSK: Ignored %lu bytes of extra " 611 "data in the end of GPSK-2", 612 (unsigned long) (end - pos)); 613 } 614 615 resp = eap_gpsk_send_gpsk_4(data, eap_get_id(reqData)); 616 if (resp == NULL) 617 return NULL; 618 619 eap_gpsk_state(data, SUCCESS); 620 ret->methodState = METHOD_DONE; 621 ret->decision = DECISION_UNCOND_SUCC; 622 623 return resp; 624} 625 626 627static struct wpabuf * eap_gpsk_send_gpsk_4(struct eap_gpsk_data *data, 628 u8 identifier) 629{ 630 struct wpabuf *resp; 631 u8 *rpos, *start; 632 size_t mlen; 633 634 wpa_printf(MSG_DEBUG, "EAP-GPSK: Sending Response/GPSK-4"); 635 636 mlen = eap_gpsk_mic_len(data->vendor, data->specifier); 637 638 resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, 1 + 2 + mlen, 639 EAP_CODE_RESPONSE, identifier); 640 if (resp == NULL) 641 return NULL; 642 643 wpabuf_put_u8(resp, EAP_GPSK_OPCODE_GPSK_4); 644 start = wpabuf_put(resp, 0); 645 646 /* No PD_Payload_3 */ 647 wpabuf_put_be16(resp, 0); 648 649 rpos = wpabuf_put(resp, mlen); 650 if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor, 651 data->specifier, start, rpos - start, rpos) < 652 0) { 653 eap_gpsk_state(data, FAILURE); 654 wpabuf_free(resp); 655 return NULL; 656 } 657 658 return resp; 659} 660 661 662static struct wpabuf * eap_gpsk_process(struct eap_sm *sm, void *priv, 663 struct eap_method_ret *ret, 664 const struct wpabuf *reqData) 665{ 666 struct eap_gpsk_data *data = priv; 667 struct wpabuf *resp; 668 const u8 *pos; 669 size_t len; 670 671 pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GPSK, reqData, &len); 672 if (pos == NULL || len < 1) { 673 ret->ignore = TRUE; 674 return NULL; 675 } 676 677 wpa_printf(MSG_DEBUG, "EAP-GPSK: Received frame: opcode %d", *pos); 678 679 ret->ignore = FALSE; 680 ret->methodState = METHOD_MAY_CONT; 681 ret->decision = DECISION_FAIL; 682 ret->allowNotifications = FALSE; 683 684 switch (*pos) { 685 case EAP_GPSK_OPCODE_GPSK_1: 686 resp = eap_gpsk_process_gpsk_1(sm, data, ret, reqData, 687 pos + 1, len - 1); 688 break; 689 case EAP_GPSK_OPCODE_GPSK_3: 690 resp = eap_gpsk_process_gpsk_3(sm, data, ret, reqData, 691 pos + 1, len - 1); 692 break; 693 default: 694 wpa_printf(MSG_DEBUG, "EAP-GPSK: Ignoring message with " 695 "unknown opcode %d", *pos); 696 ret->ignore = TRUE; 697 return NULL; 698 } 699 700 return resp; 701} 702 703 704static Boolean eap_gpsk_isKeyAvailable(struct eap_sm *sm, void *priv) 705{ 706 struct eap_gpsk_data *data = priv; 707 return data->state == SUCCESS; 708} 709 710 711static u8 * eap_gpsk_getKey(struct eap_sm *sm, void *priv, size_t *len) 712{ 713 struct eap_gpsk_data *data = priv; 714 u8 *key; 715 716 if (data->state != SUCCESS) 717 return NULL; 718 719 key = os_malloc(EAP_MSK_LEN); 720 if (key == NULL) 721 return NULL; 722 os_memcpy(key, data->msk, EAP_MSK_LEN); 723 *len = EAP_MSK_LEN; 724 725 return key; 726} 727 728 729static u8 * eap_gpsk_get_emsk(struct eap_sm *sm, void *priv, size_t *len) 730{ 731 struct eap_gpsk_data *data = priv; 732 u8 *key; 733 734 if (data->state != SUCCESS) 735 return NULL; 736 737 key = os_malloc(EAP_EMSK_LEN); 738 if (key == NULL) 739 return NULL; 740 os_memcpy(key, data->emsk, EAP_EMSK_LEN); 741 *len = EAP_EMSK_LEN; 742 743 return key; 744} 745 746 747static u8 * eap_gpsk_get_session_id(struct eap_sm *sm, void *priv, size_t *len) 748{ 749 struct eap_gpsk_data *data = priv; 750 u8 *sid; 751 752 if (data->state != SUCCESS) 753 return NULL; 754 755 sid = os_malloc(data->id_len); 756 if (sid == NULL) 757 return NULL; 758 os_memcpy(sid, data->session_id, data->id_len); 759 *len = data->id_len; 760 761 return sid; 762} 763 764 765int eap_peer_gpsk_register(void) 766{ 767 struct eap_method *eap; 768 int ret; 769 770 eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, 771 EAP_VENDOR_IETF, EAP_TYPE_GPSK, "GPSK"); 772 if (eap == NULL) 773 return -1; 774 775 eap->init = eap_gpsk_init; 776 eap->deinit = eap_gpsk_deinit; 777 eap->process = eap_gpsk_process; 778 eap->isKeyAvailable = eap_gpsk_isKeyAvailable; 779 eap->getKey = eap_gpsk_getKey; 780 eap->get_emsk = eap_gpsk_get_emsk; 781 eap->getSessionId = eap_gpsk_get_session_id; 782 783 ret = eap_peer_method_register(eap); 784 if (ret) 785 eap_peer_method_free(eap); 786 return ret; 787} 788