1 /* 2 * hostapd / EAP-GPSK (RFC 5433) server 3 * Copyright (c) 2006-2007, 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_server/eap_i.h" 14 #include "eap_common/eap_gpsk_common.h" 15 16 17 struct eap_gpsk_data { 18 enum { GPSK_1, GPSK_3, SUCCESS, FAILURE } state; 19 u8 rand_server[EAP_GPSK_RAND_LEN]; 20 u8 rand_peer[EAP_GPSK_RAND_LEN]; 21 u8 msk[EAP_MSK_LEN]; 22 u8 emsk[EAP_EMSK_LEN]; 23 u8 sk[EAP_GPSK_MAX_SK_LEN]; 24 size_t sk_len; 25 u8 pk[EAP_GPSK_MAX_PK_LEN]; 26 size_t pk_len; 27 u8 session_id[128]; 28 size_t id_len; 29 u8 *id_peer; 30 size_t id_peer_len; 31 #define MAX_NUM_CSUITES 2 32 struct eap_gpsk_csuite csuite_list[MAX_NUM_CSUITES]; 33 size_t csuite_count; 34 int vendor; /* CSuite/Vendor */ 35 int specifier; /* CSuite/Specifier */ 36 }; 37 38 39 static const char * eap_gpsk_state_txt(int state) 40 { 41 switch (state) { 42 case GPSK_1: 43 return "GPSK-1"; 44 case GPSK_3: 45 return "GPSK-3"; 46 case SUCCESS: 47 return "SUCCESS"; 48 case FAILURE: 49 return "FAILURE"; 50 default: 51 return "?"; 52 } 53 } 54 55 56 static void eap_gpsk_state(struct eap_gpsk_data *data, int state) 57 { 58 wpa_printf(MSG_DEBUG, "EAP-GPSK: %s -> %s", 59 eap_gpsk_state_txt(data->state), 60 eap_gpsk_state_txt(state)); 61 data->state = state; 62 } 63 64 65 static void * eap_gpsk_init(struct eap_sm *sm) 66 { 67 struct eap_gpsk_data *data; 68 69 data = os_zalloc(sizeof(*data)); 70 if (data == NULL) 71 return NULL; 72 data->state = GPSK_1; 73 74 data->csuite_count = 0; 75 if (eap_gpsk_supported_ciphersuite(EAP_GPSK_VENDOR_IETF, 76 EAP_GPSK_CIPHER_AES)) { 77 WPA_PUT_BE32(data->csuite_list[data->csuite_count].vendor, 78 EAP_GPSK_VENDOR_IETF); 79 WPA_PUT_BE16(data->csuite_list[data->csuite_count].specifier, 80 EAP_GPSK_CIPHER_AES); 81 data->csuite_count++; 82 } 83 if (eap_gpsk_supported_ciphersuite(EAP_GPSK_VENDOR_IETF, 84 EAP_GPSK_CIPHER_SHA256)) { 85 WPA_PUT_BE32(data->csuite_list[data->csuite_count].vendor, 86 EAP_GPSK_VENDOR_IETF); 87 WPA_PUT_BE16(data->csuite_list[data->csuite_count].specifier, 88 EAP_GPSK_CIPHER_SHA256); 89 data->csuite_count++; 90 } 91 92 return data; 93 } 94 95 96 static void eap_gpsk_reset(struct eap_sm *sm, void *priv) 97 { 98 struct eap_gpsk_data *data = priv; 99 os_free(data->id_peer); 100 bin_clear_free(data, sizeof(*data)); 101 } 102 103 104 static struct wpabuf * eap_gpsk_build_gpsk_1(struct eap_sm *sm, 105 struct eap_gpsk_data *data, u8 id) 106 { 107 size_t len; 108 struct wpabuf *req; 109 110 wpa_printf(MSG_DEBUG, "EAP-GPSK: Request/GPSK-1"); 111 112 if (random_get_bytes(data->rand_server, EAP_GPSK_RAND_LEN)) { 113 wpa_printf(MSG_ERROR, "EAP-GPSK: Failed to get random data"); 114 eap_gpsk_state(data, FAILURE); 115 return NULL; 116 } 117 wpa_hexdump(MSG_MSGDUMP, "EAP-GPSK: RAND_Server", 118 data->rand_server, EAP_GPSK_RAND_LEN); 119 120 len = 1 + 2 + sm->server_id_len + EAP_GPSK_RAND_LEN + 2 + 121 data->csuite_count * sizeof(struct eap_gpsk_csuite); 122 req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, len, 123 EAP_CODE_REQUEST, id); 124 if (req == NULL) { 125 wpa_printf(MSG_ERROR, "EAP-GPSK: Failed to allocate memory " 126 "for request/GPSK-1"); 127 eap_gpsk_state(data, FAILURE); 128 return NULL; 129 } 130 131 wpabuf_put_u8(req, EAP_GPSK_OPCODE_GPSK_1); 132 wpabuf_put_be16(req, sm->server_id_len); 133 wpabuf_put_data(req, sm->server_id, sm->server_id_len); 134 wpabuf_put_data(req, data->rand_server, EAP_GPSK_RAND_LEN); 135 wpabuf_put_be16(req, 136 data->csuite_count * sizeof(struct eap_gpsk_csuite)); 137 wpabuf_put_data(req, data->csuite_list, 138 data->csuite_count * sizeof(struct eap_gpsk_csuite)); 139 140 return req; 141 } 142 143 144 static struct wpabuf * eap_gpsk_build_gpsk_3(struct eap_sm *sm, 145 struct eap_gpsk_data *data, u8 id) 146 { 147 u8 *pos, *start; 148 size_t len, miclen; 149 struct eap_gpsk_csuite *csuite; 150 struct wpabuf *req; 151 152 wpa_printf(MSG_DEBUG, "EAP-GPSK: Request/GPSK-3"); 153 154 miclen = eap_gpsk_mic_len(data->vendor, data->specifier); 155 len = 1 + 2 * EAP_GPSK_RAND_LEN + 2 + sm->server_id_len + 156 sizeof(struct eap_gpsk_csuite) + 2 + miclen; 157 req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, len, 158 EAP_CODE_REQUEST, id); 159 if (req == NULL) { 160 wpa_printf(MSG_ERROR, "EAP-GPSK: Failed to allocate memory " 161 "for request/GPSK-3"); 162 eap_gpsk_state(data, FAILURE); 163 return NULL; 164 } 165 166 wpabuf_put_u8(req, EAP_GPSK_OPCODE_GPSK_3); 167 start = wpabuf_put(req, 0); 168 169 wpabuf_put_data(req, data->rand_peer, EAP_GPSK_RAND_LEN); 170 wpabuf_put_data(req, data->rand_server, EAP_GPSK_RAND_LEN); 171 wpabuf_put_be16(req, sm->server_id_len); 172 wpabuf_put_data(req, sm->server_id, sm->server_id_len); 173 csuite = wpabuf_put(req, sizeof(*csuite)); 174 WPA_PUT_BE32(csuite->vendor, data->vendor); 175 WPA_PUT_BE16(csuite->specifier, data->specifier); 176 177 /* no PD_Payload_2 */ 178 wpabuf_put_be16(req, 0); 179 180 pos = wpabuf_put(req, miclen); 181 if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor, 182 data->specifier, start, pos - start, pos) < 0) 183 { 184 wpabuf_free(req); 185 eap_gpsk_state(data, FAILURE); 186 return NULL; 187 } 188 189 return req; 190 } 191 192 193 static struct wpabuf * eap_gpsk_buildReq(struct eap_sm *sm, void *priv, u8 id) 194 { 195 struct eap_gpsk_data *data = priv; 196 197 switch (data->state) { 198 case GPSK_1: 199 return eap_gpsk_build_gpsk_1(sm, data, id); 200 case GPSK_3: 201 return eap_gpsk_build_gpsk_3(sm, data, id); 202 default: 203 wpa_printf(MSG_DEBUG, "EAP-GPSK: Unknown state %d in buildReq", 204 data->state); 205 break; 206 } 207 return NULL; 208 } 209 210 211 static Boolean eap_gpsk_check(struct eap_sm *sm, void *priv, 212 struct wpabuf *respData) 213 { 214 struct eap_gpsk_data *data = priv; 215 const u8 *pos; 216 size_t len; 217 218 pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GPSK, respData, &len); 219 if (pos == NULL || len < 1) { 220 wpa_printf(MSG_INFO, "EAP-GPSK: Invalid frame"); 221 return TRUE; 222 } 223 224 wpa_printf(MSG_DEBUG, "EAP-GPSK: Received frame: opcode=%d", *pos); 225 226 if (data->state == GPSK_1 && *pos == EAP_GPSK_OPCODE_GPSK_2) 227 return FALSE; 228 229 if (data->state == GPSK_3 && *pos == EAP_GPSK_OPCODE_GPSK_4) 230 return FALSE; 231 232 wpa_printf(MSG_INFO, "EAP-GPSK: Unexpected opcode=%d in state=%d", 233 *pos, data->state); 234 235 return TRUE; 236 } 237 238 239 static void eap_gpsk_process_gpsk_2(struct eap_sm *sm, 240 struct eap_gpsk_data *data, 241 const u8 *payload, size_t payloadlen) 242 { 243 const u8 *pos, *end; 244 u16 alen; 245 const struct eap_gpsk_csuite *csuite; 246 size_t i, miclen; 247 u8 mic[EAP_GPSK_MAX_MIC_LEN]; 248 249 if (data->state != GPSK_1) 250 return; 251 252 wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Response/GPSK-2"); 253 254 pos = payload; 255 end = payload + payloadlen; 256 257 if (end - pos < 2) { 258 wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " 259 "ID_Peer length"); 260 eap_gpsk_state(data, FAILURE); 261 return; 262 } 263 alen = WPA_GET_BE16(pos); 264 pos += 2; 265 if (end - pos < alen) { 266 wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " 267 "ID_Peer"); 268 eap_gpsk_state(data, FAILURE); 269 return; 270 } 271 os_free(data->id_peer); 272 data->id_peer = os_memdup(pos, alen); 273 if (data->id_peer == NULL) { 274 wpa_printf(MSG_DEBUG, "EAP-GPSK: Not enough memory to store " 275 "%d-octet ID_Peer", alen); 276 return; 277 } 278 data->id_peer_len = alen; 279 wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Peer", 280 data->id_peer, data->id_peer_len); 281 pos += alen; 282 283 if (end - pos < 2) { 284 wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " 285 "ID_Server length"); 286 eap_gpsk_state(data, FAILURE); 287 return; 288 } 289 alen = WPA_GET_BE16(pos); 290 pos += 2; 291 if (end - pos < alen) { 292 wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " 293 "ID_Server"); 294 eap_gpsk_state(data, FAILURE); 295 return; 296 } 297 if (alen != sm->server_id_len || 298 os_memcmp(pos, sm->server_id, alen) != 0) { 299 wpa_printf(MSG_DEBUG, "EAP-GPSK: ID_Server in GPSK-1 and " 300 "GPSK-2 did not match"); 301 eap_gpsk_state(data, FAILURE); 302 return; 303 } 304 pos += alen; 305 306 if (end - pos < EAP_GPSK_RAND_LEN) { 307 wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " 308 "RAND_Peer"); 309 eap_gpsk_state(data, FAILURE); 310 return; 311 } 312 os_memcpy(data->rand_peer, pos, EAP_GPSK_RAND_LEN); 313 wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Peer", 314 data->rand_peer, EAP_GPSK_RAND_LEN); 315 pos += EAP_GPSK_RAND_LEN; 316 317 if (end - pos < EAP_GPSK_RAND_LEN) { 318 wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " 319 "RAND_Server"); 320 eap_gpsk_state(data, FAILURE); 321 return; 322 } 323 if (os_memcmp(data->rand_server, pos, EAP_GPSK_RAND_LEN) != 0) { 324 wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1 and " 325 "GPSK-2 did not match"); 326 wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1", 327 data->rand_server, EAP_GPSK_RAND_LEN); 328 wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-2", 329 pos, EAP_GPSK_RAND_LEN); 330 eap_gpsk_state(data, FAILURE); 331 return; 332 } 333 pos += EAP_GPSK_RAND_LEN; 334 335 if (end - pos < 2) { 336 wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " 337 "CSuite_List length"); 338 eap_gpsk_state(data, FAILURE); 339 return; 340 } 341 alen = WPA_GET_BE16(pos); 342 pos += 2; 343 if (end - pos < alen) { 344 wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " 345 "CSuite_List"); 346 eap_gpsk_state(data, FAILURE); 347 return; 348 } 349 if (alen != data->csuite_count * sizeof(struct eap_gpsk_csuite) || 350 os_memcmp(pos, data->csuite_list, alen) != 0) { 351 wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_List in GPSK-1 and " 352 "GPSK-2 did not match"); 353 eap_gpsk_state(data, FAILURE); 354 return; 355 } 356 pos += alen; 357 358 if (end - pos < (int) sizeof(*csuite)) { 359 wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " 360 "CSuite_Sel"); 361 eap_gpsk_state(data, FAILURE); 362 return; 363 } 364 csuite = (const struct eap_gpsk_csuite *) pos; 365 for (i = 0; i < data->csuite_count; i++) { 366 if (os_memcmp(csuite, &data->csuite_list[i], sizeof(*csuite)) 367 == 0) 368 break; 369 } 370 if (i == data->csuite_count) { 371 wpa_printf(MSG_DEBUG, "EAP-GPSK: Peer selected unsupported " 372 "ciphersuite %d:%d", 373 WPA_GET_BE32(csuite->vendor), 374 WPA_GET_BE16(csuite->specifier)); 375 eap_gpsk_state(data, FAILURE); 376 return; 377 } 378 data->vendor = WPA_GET_BE32(csuite->vendor); 379 data->specifier = WPA_GET_BE16(csuite->specifier); 380 wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_Sel %d:%d", 381 data->vendor, data->specifier); 382 pos += sizeof(*csuite); 383 384 if (end - pos < 2) { 385 wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " 386 "PD_Payload_1 length"); 387 eap_gpsk_state(data, FAILURE); 388 return; 389 } 390 alen = WPA_GET_BE16(pos); 391 pos += 2; 392 if (end - pos < alen) { 393 wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " 394 "PD_Payload_1"); 395 eap_gpsk_state(data, FAILURE); 396 return; 397 } 398 wpa_hexdump(MSG_DEBUG, "EAP-GPSK: PD_Payload_1", pos, alen); 399 pos += alen; 400 401 if (sm->user == NULL || sm->user->password == NULL) { 402 wpa_printf(MSG_INFO, "EAP-GPSK: No PSK/password configured " 403 "for the user"); 404 eap_gpsk_state(data, FAILURE); 405 return; 406 } 407 408 if (eap_gpsk_derive_keys(sm->user->password, sm->user->password_len, 409 data->vendor, data->specifier, 410 data->rand_peer, data->rand_server, 411 data->id_peer, data->id_peer_len, 412 sm->server_id, sm->server_id_len, 413 data->msk, data->emsk, 414 data->sk, &data->sk_len, 415 data->pk, &data->pk_len) < 0) { 416 wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to derive keys"); 417 eap_gpsk_state(data, FAILURE); 418 return; 419 } 420 421 if (eap_gpsk_derive_session_id(sm->user->password, 422 sm->user->password_len, 423 data->vendor, data->specifier, 424 data->rand_peer, data->rand_server, 425 data->id_peer, data->id_peer_len, 426 sm->server_id, sm->server_id_len, 427 EAP_TYPE_GPSK, 428 data->session_id, &data->id_len) < 0) { 429 wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to derive Session-Id"); 430 eap_gpsk_state(data, FAILURE); 431 return; 432 } 433 wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Derived Session-Id", 434 data->session_id, data->id_len); 435 436 miclen = eap_gpsk_mic_len(data->vendor, data->specifier); 437 if (end - pos < (int) miclen) { 438 wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for MIC " 439 "(left=%lu miclen=%lu)", 440 (unsigned long) (end - pos), 441 (unsigned long) miclen); 442 eap_gpsk_state(data, FAILURE); 443 return; 444 } 445 if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor, 446 data->specifier, payload, pos - payload, mic) 447 < 0) { 448 wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to compute MIC"); 449 eap_gpsk_state(data, FAILURE); 450 return; 451 } 452 if (os_memcmp_const(mic, pos, miclen) != 0) { 453 wpa_printf(MSG_INFO, "EAP-GPSK: Incorrect MIC in GPSK-2"); 454 wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Received MIC", pos, miclen); 455 wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Computed MIC", mic, miclen); 456 eap_gpsk_state(data, FAILURE); 457 return; 458 } 459 pos += miclen; 460 461 if (pos != end) { 462 wpa_printf(MSG_DEBUG, "EAP-GPSK: Ignored %lu bytes of extra " 463 "data in the end of GPSK-2", 464 (unsigned long) (end - pos)); 465 } 466 467 eap_gpsk_state(data, GPSK_3); 468 } 469 470 471 static void eap_gpsk_process_gpsk_4(struct eap_sm *sm, 472 struct eap_gpsk_data *data, 473 const u8 *payload, size_t payloadlen) 474 { 475 const u8 *pos, *end; 476 u16 alen; 477 size_t miclen; 478 u8 mic[EAP_GPSK_MAX_MIC_LEN]; 479 480 if (data->state != GPSK_3) 481 return; 482 483 wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Response/GPSK-4"); 484 485 pos = payload; 486 end = payload + payloadlen; 487 488 if (end - pos < 2) { 489 wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " 490 "PD_Payload_1 length"); 491 eap_gpsk_state(data, FAILURE); 492 return; 493 } 494 alen = WPA_GET_BE16(pos); 495 pos += 2; 496 if (end - pos < alen) { 497 wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " 498 "PD_Payload_1"); 499 eap_gpsk_state(data, FAILURE); 500 return; 501 } 502 wpa_hexdump(MSG_DEBUG, "EAP-GPSK: PD_Payload_1", pos, alen); 503 pos += alen; 504 505 miclen = eap_gpsk_mic_len(data->vendor, data->specifier); 506 if (end - pos < (int) miclen) { 507 wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for MIC " 508 "(left=%lu miclen=%lu)", 509 (unsigned long) (end - pos), 510 (unsigned long) miclen); 511 eap_gpsk_state(data, FAILURE); 512 return; 513 } 514 if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor, 515 data->specifier, payload, pos - payload, mic) 516 < 0) { 517 wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to compute MIC"); 518 eap_gpsk_state(data, FAILURE); 519 return; 520 } 521 if (os_memcmp_const(mic, pos, miclen) != 0) { 522 wpa_printf(MSG_INFO, "EAP-GPSK: Incorrect MIC in GPSK-4"); 523 wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Received MIC", pos, miclen); 524 wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Computed MIC", mic, miclen); 525 eap_gpsk_state(data, FAILURE); 526 return; 527 } 528 pos += miclen; 529 530 if (pos != end) { 531 wpa_printf(MSG_DEBUG, "EAP-GPSK: Ignored %lu bytes of extra " 532 "data in the end of GPSK-4", 533 (unsigned long) (end - pos)); 534 } 535 536 eap_gpsk_state(data, SUCCESS); 537 } 538 539 540 static void eap_gpsk_process(struct eap_sm *sm, void *priv, 541 struct wpabuf *respData) 542 { 543 struct eap_gpsk_data *data = priv; 544 const u8 *pos; 545 size_t len; 546 547 pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GPSK, respData, &len); 548 if (pos == NULL || len < 1) 549 return; 550 551 switch (*pos) { 552 case EAP_GPSK_OPCODE_GPSK_2: 553 eap_gpsk_process_gpsk_2(sm, data, pos + 1, len - 1); 554 break; 555 case EAP_GPSK_OPCODE_GPSK_4: 556 eap_gpsk_process_gpsk_4(sm, data, pos + 1, len - 1); 557 break; 558 } 559 } 560 561 562 static Boolean eap_gpsk_isDone(struct eap_sm *sm, void *priv) 563 { 564 struct eap_gpsk_data *data = priv; 565 return data->state == SUCCESS || data->state == FAILURE; 566 } 567 568 569 static u8 * eap_gpsk_getKey(struct eap_sm *sm, void *priv, size_t *len) 570 { 571 struct eap_gpsk_data *data = priv; 572 u8 *key; 573 574 if (data->state != SUCCESS) 575 return NULL; 576 577 key = os_memdup(data->msk, EAP_MSK_LEN); 578 if (key == NULL) 579 return NULL; 580 *len = EAP_MSK_LEN; 581 582 return key; 583 } 584 585 586 static u8 * eap_gpsk_get_emsk(struct eap_sm *sm, void *priv, size_t *len) 587 { 588 struct eap_gpsk_data *data = priv; 589 u8 *key; 590 591 if (data->state != SUCCESS) 592 return NULL; 593 594 key = os_memdup(data->emsk, EAP_EMSK_LEN); 595 if (key == NULL) 596 return NULL; 597 *len = EAP_EMSK_LEN; 598 599 return key; 600 } 601 602 603 static Boolean eap_gpsk_isSuccess(struct eap_sm *sm, void *priv) 604 { 605 struct eap_gpsk_data *data = priv; 606 return data->state == SUCCESS; 607 } 608 609 610 static u8 * eap_gpsk_get_session_id(struct eap_sm *sm, void *priv, size_t *len) 611 { 612 struct eap_gpsk_data *data = priv; 613 u8 *sid; 614 615 if (data->state != SUCCESS) 616 return NULL; 617 618 sid = os_memdup(data->session_id, data->id_len); 619 if (sid == NULL) 620 return NULL; 621 *len = data->id_len; 622 623 return sid; 624 } 625 626 627 int eap_server_gpsk_register(void) 628 { 629 struct eap_method *eap; 630 631 eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, 632 EAP_VENDOR_IETF, EAP_TYPE_GPSK, "GPSK"); 633 if (eap == NULL) 634 return -1; 635 636 eap->init = eap_gpsk_init; 637 eap->reset = eap_gpsk_reset; 638 eap->buildReq = eap_gpsk_buildReq; 639 eap->check = eap_gpsk_check; 640 eap->process = eap_gpsk_process; 641 eap->isDone = eap_gpsk_isDone; 642 eap->getKey = eap_gpsk_getKey; 643 eap->isSuccess = eap_gpsk_isSuccess; 644 eap->get_emsk = eap_gpsk_get_emsk; 645 eap->getSessionId = eap_gpsk_get_session_id; 646 647 return eap_server_method_register(eap); 648 } 649