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