1 /* 2 * hostapd / EAP-PEAP (draft-josefsson-pppext-eap-tls-eap-10.txt) 3 * Copyright (c) 2004-2008, Jouni Malinen <j (at) 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/sha1.h" 13 #include "crypto/tls.h" 14 #include "crypto/random.h" 15 #include "eap_i.h" 16 #include "eap_tls_common.h" 17 #include "eap_common/eap_tlv_common.h" 18 #include "eap_common/eap_peap_common.h" 19 #include "tncs.h" 20 21 22 /* Maximum supported PEAP version 23 * 0 = Microsoft's PEAP version 0; draft-kamath-pppext-peapv0-00.txt 24 * 1 = draft-josefsson-ppext-eap-tls-eap-05.txt 25 */ 26 #define EAP_PEAP_VERSION 1 27 28 29 static void eap_peap_reset(struct eap_sm *sm, void *priv); 30 31 32 struct eap_peap_data { 33 struct eap_ssl_data ssl; 34 enum { 35 START, PHASE1, PHASE1_ID2, PHASE2_START, PHASE2_ID, 36 PHASE2_METHOD, PHASE2_SOH, 37 PHASE2_TLV, SUCCESS_REQ, FAILURE_REQ, SUCCESS, FAILURE 38 } state; 39 40 int peap_version; 41 int recv_version; 42 const struct eap_method *phase2_method; 43 void *phase2_priv; 44 int force_version; 45 struct wpabuf *pending_phase2_resp; 46 enum { TLV_REQ_NONE, TLV_REQ_SUCCESS, TLV_REQ_FAILURE } tlv_request; 47 int crypto_binding_sent; 48 int crypto_binding_used; 49 enum { NO_BINDING, OPTIONAL_BINDING, REQUIRE_BINDING } crypto_binding; 50 u8 binding_nonce[32]; 51 u8 ipmk[40]; 52 u8 cmk[20]; 53 u8 *phase2_key; 54 size_t phase2_key_len; 55 struct wpabuf *soh_response; 56 }; 57 58 59 static const char * eap_peap_state_txt(int state) 60 { 61 switch (state) { 62 case START: 63 return "START"; 64 case PHASE1: 65 return "PHASE1"; 66 case PHASE1_ID2: 67 return "PHASE1_ID2"; 68 case PHASE2_START: 69 return "PHASE2_START"; 70 case PHASE2_ID: 71 return "PHASE2_ID"; 72 case PHASE2_METHOD: 73 return "PHASE2_METHOD"; 74 case PHASE2_SOH: 75 return "PHASE2_SOH"; 76 case PHASE2_TLV: 77 return "PHASE2_TLV"; 78 case SUCCESS_REQ: 79 return "SUCCESS_REQ"; 80 case FAILURE_REQ: 81 return "FAILURE_REQ"; 82 case SUCCESS: 83 return "SUCCESS"; 84 case FAILURE: 85 return "FAILURE"; 86 default: 87 return "Unknown?!"; 88 } 89 } 90 91 92 static void eap_peap_state(struct eap_peap_data *data, int state) 93 { 94 wpa_printf(MSG_DEBUG, "EAP-PEAP: %s -> %s", 95 eap_peap_state_txt(data->state), 96 eap_peap_state_txt(state)); 97 data->state = state; 98 } 99 100 101 static void eap_peap_req_success(struct eap_sm *sm, 102 struct eap_peap_data *data) 103 { 104 if (data->state == FAILURE || data->state == FAILURE_REQ) { 105 eap_peap_state(data, FAILURE); 106 return; 107 } 108 109 if (data->peap_version == 0) { 110 data->tlv_request = TLV_REQ_SUCCESS; 111 eap_peap_state(data, PHASE2_TLV); 112 } else { 113 eap_peap_state(data, SUCCESS_REQ); 114 } 115 } 116 117 118 static void eap_peap_req_failure(struct eap_sm *sm, 119 struct eap_peap_data *data) 120 { 121 if (data->state == FAILURE || data->state == FAILURE_REQ || 122 data->state == SUCCESS_REQ || data->tlv_request != TLV_REQ_NONE) { 123 eap_peap_state(data, FAILURE); 124 return; 125 } 126 127 if (data->peap_version == 0) { 128 data->tlv_request = TLV_REQ_FAILURE; 129 eap_peap_state(data, PHASE2_TLV); 130 } else { 131 eap_peap_state(data, FAILURE_REQ); 132 } 133 } 134 135 136 static void * eap_peap_init(struct eap_sm *sm) 137 { 138 struct eap_peap_data *data; 139 140 data = os_zalloc(sizeof(*data)); 141 if (data == NULL) 142 return NULL; 143 data->peap_version = EAP_PEAP_VERSION; 144 data->force_version = -1; 145 if (sm->user && sm->user->force_version >= 0) { 146 data->force_version = sm->user->force_version; 147 wpa_printf(MSG_DEBUG, "EAP-PEAP: forcing version %d", 148 data->force_version); 149 data->peap_version = data->force_version; 150 } 151 data->state = START; 152 data->crypto_binding = OPTIONAL_BINDING; 153 154 if (eap_server_tls_ssl_init(sm, &data->ssl, 0)) { 155 wpa_printf(MSG_INFO, "EAP-PEAP: Failed to initialize SSL."); 156 eap_peap_reset(sm, data); 157 return NULL; 158 } 159 160 return data; 161 } 162 163 164 static void eap_peap_reset(struct eap_sm *sm, void *priv) 165 { 166 struct eap_peap_data *data = priv; 167 if (data == NULL) 168 return; 169 if (data->phase2_priv && data->phase2_method) 170 data->phase2_method->reset(sm, data->phase2_priv); 171 eap_server_tls_ssl_deinit(sm, &data->ssl); 172 wpabuf_free(data->pending_phase2_resp); 173 os_free(data->phase2_key); 174 wpabuf_free(data->soh_response); 175 bin_clear_free(data, sizeof(*data)); 176 } 177 178 179 static struct wpabuf * eap_peap_build_start(struct eap_sm *sm, 180 struct eap_peap_data *data, u8 id) 181 { 182 struct wpabuf *req; 183 184 req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PEAP, 1, 185 EAP_CODE_REQUEST, id); 186 if (req == NULL) { 187 wpa_printf(MSG_ERROR, "EAP-PEAP: Failed to allocate memory for" 188 " request"); 189 eap_peap_state(data, FAILURE); 190 return NULL; 191 } 192 193 wpabuf_put_u8(req, EAP_TLS_FLAGS_START | data->peap_version); 194 195 eap_peap_state(data, PHASE1); 196 197 return req; 198 } 199 200 201 static struct wpabuf * eap_peap_build_phase2_req(struct eap_sm *sm, 202 struct eap_peap_data *data, 203 u8 id) 204 { 205 struct wpabuf *buf, *encr_req, msgbuf; 206 const u8 *req; 207 size_t req_len; 208 209 if (data->phase2_method == NULL || data->phase2_priv == NULL) { 210 wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 method not ready"); 211 return NULL; 212 } 213 buf = data->phase2_method->buildReq(sm, data->phase2_priv, id); 214 if (buf == NULL) 215 return NULL; 216 217 req = wpabuf_head(buf); 218 req_len = wpabuf_len(buf); 219 wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 data", 220 req, req_len); 221 222 if (data->peap_version == 0 && 223 data->phase2_method->method != EAP_TYPE_TLV) { 224 req += sizeof(struct eap_hdr); 225 req_len -= sizeof(struct eap_hdr); 226 } 227 228 wpabuf_set(&msgbuf, req, req_len); 229 encr_req = eap_server_tls_encrypt(sm, &data->ssl, &msgbuf); 230 wpabuf_free(buf); 231 232 return encr_req; 233 } 234 235 236 #ifdef EAP_SERVER_TNC 237 static struct wpabuf * eap_peap_build_phase2_soh(struct eap_sm *sm, 238 struct eap_peap_data *data, 239 u8 id) 240 { 241 struct wpabuf *buf1, *buf, *encr_req, msgbuf; 242 const u8 *req; 243 size_t req_len; 244 245 buf1 = tncs_build_soh_request(); 246 if (buf1 == NULL) 247 return NULL; 248 249 buf = eap_msg_alloc(EAP_VENDOR_MICROSOFT, 0x21, wpabuf_len(buf1), 250 EAP_CODE_REQUEST, id); 251 if (buf == NULL) { 252 wpabuf_free(buf1); 253 return NULL; 254 } 255 wpabuf_put_buf(buf, buf1); 256 wpabuf_free(buf1); 257 258 req = wpabuf_head(buf); 259 req_len = wpabuf_len(buf); 260 261 wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 SOH data", 262 req, req_len); 263 264 req += sizeof(struct eap_hdr); 265 req_len -= sizeof(struct eap_hdr); 266 wpabuf_set(&msgbuf, req, req_len); 267 268 encr_req = eap_server_tls_encrypt(sm, &data->ssl, &msgbuf); 269 wpabuf_free(buf); 270 271 return encr_req; 272 } 273 #endif /* EAP_SERVER_TNC */ 274 275 276 static void eap_peap_get_isk(struct eap_peap_data *data, 277 u8 *isk, size_t isk_len) 278 { 279 size_t key_len; 280 281 os_memset(isk, 0, isk_len); 282 if (data->phase2_key == NULL) 283 return; 284 285 key_len = data->phase2_key_len; 286 if (key_len > isk_len) 287 key_len = isk_len; 288 os_memcpy(isk, data->phase2_key, key_len); 289 } 290 291 292 static int eap_peap_derive_cmk(struct eap_sm *sm, struct eap_peap_data *data) 293 { 294 u8 *tk; 295 u8 isk[32], imck[60]; 296 297 /* 298 * Tunnel key (TK) is the first 60 octets of the key generated by 299 * phase 1 of PEAP (based on TLS). 300 */ 301 tk = eap_server_tls_derive_key(sm, &data->ssl, "client EAP encryption", 302 EAP_TLS_KEY_LEN); 303 if (tk == NULL) 304 return -1; 305 wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TK", tk, 60); 306 307 eap_peap_get_isk(data, isk, sizeof(isk)); 308 wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: ISK", isk, sizeof(isk)); 309 310 /* 311 * IPMK Seed = "Inner Methods Compound Keys" | ISK 312 * TempKey = First 40 octets of TK 313 * IPMK|CMK = PRF+(TempKey, IPMK Seed, 60) 314 * (note: draft-josefsson-pppext-eap-tls-eap-10.txt includes a space 315 * in the end of the label just before ISK; is that just a typo?) 316 */ 317 wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TempKey", tk, 40); 318 if (peap_prfplus(data->peap_version, tk, 40, 319 "Inner Methods Compound Keys", 320 isk, sizeof(isk), imck, sizeof(imck)) < 0) { 321 os_free(tk); 322 return -1; 323 } 324 wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IMCK (IPMKj)", 325 imck, sizeof(imck)); 326 327 os_free(tk); 328 329 /* TODO: fast-connect: IPMK|CMK = TK */ 330 os_memcpy(data->ipmk, imck, 40); 331 wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IPMK (S-IPMKj)", data->ipmk, 40); 332 os_memcpy(data->cmk, imck + 40, 20); 333 wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK (CMKj)", data->cmk, 20); 334 335 return 0; 336 } 337 338 339 static struct wpabuf * eap_peap_build_phase2_tlv(struct eap_sm *sm, 340 struct eap_peap_data *data, 341 u8 id) 342 { 343 struct wpabuf *buf, *encr_req; 344 size_t mlen; 345 346 mlen = 6; /* Result TLV */ 347 if (data->peap_version == 0 && data->tlv_request == TLV_REQ_SUCCESS && 348 data->crypto_binding != NO_BINDING) { 349 mlen += 60; /* Cryptobinding TLV */ 350 #ifdef EAP_SERVER_TNC 351 if (data->soh_response) 352 mlen += wpabuf_len(data->soh_response); 353 #endif /* EAP_SERVER_TNC */ 354 } 355 356 buf = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLV, mlen, 357 EAP_CODE_REQUEST, id); 358 if (buf == NULL) 359 return NULL; 360 361 wpabuf_put_u8(buf, 0x80); /* Mandatory */ 362 wpabuf_put_u8(buf, EAP_TLV_RESULT_TLV); 363 /* Length */ 364 wpabuf_put_be16(buf, 2); 365 /* Status */ 366 wpabuf_put_be16(buf, data->tlv_request == TLV_REQ_SUCCESS ? 367 EAP_TLV_RESULT_SUCCESS : EAP_TLV_RESULT_FAILURE); 368 369 if (data->peap_version == 0 && data->tlv_request == TLV_REQ_SUCCESS && 370 data->crypto_binding != NO_BINDING) { 371 u8 *mac; 372 u8 eap_type = EAP_TYPE_PEAP; 373 const u8 *addr[2]; 374 size_t len[2]; 375 u16 tlv_type; 376 377 #ifdef EAP_SERVER_TNC 378 if (data->soh_response) { 379 wpa_printf(MSG_DEBUG, "EAP-PEAP: Adding MS-SOH " 380 "Response TLV"); 381 wpabuf_put_buf(buf, data->soh_response); 382 wpabuf_free(data->soh_response); 383 data->soh_response = NULL; 384 } 385 #endif /* EAP_SERVER_TNC */ 386 387 if (eap_peap_derive_cmk(sm, data) < 0 || 388 random_get_bytes(data->binding_nonce, 32)) { 389 wpabuf_free(buf); 390 return NULL; 391 } 392 393 /* Compound_MAC: HMAC-SHA1-160(cryptobinding TLV | EAP type) */ 394 addr[0] = wpabuf_put(buf, 0); 395 len[0] = 60; 396 addr[1] = &eap_type; 397 len[1] = 1; 398 399 tlv_type = EAP_TLV_CRYPTO_BINDING_TLV; 400 wpabuf_put_be16(buf, tlv_type); 401 wpabuf_put_be16(buf, 56); 402 403 wpabuf_put_u8(buf, 0); /* Reserved */ 404 wpabuf_put_u8(buf, data->peap_version); /* Version */ 405 wpabuf_put_u8(buf, data->recv_version); /* RecvVersion */ 406 wpabuf_put_u8(buf, 0); /* SubType: 0 = Request, 1 = Response */ 407 wpabuf_put_data(buf, data->binding_nonce, 32); /* Nonce */ 408 mac = wpabuf_put(buf, 20); /* Compound_MAC */ 409 wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC CMK", 410 data->cmk, 20); 411 wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 1", 412 addr[0], len[0]); 413 wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 2", 414 addr[1], len[1]); 415 hmac_sha1_vector(data->cmk, 20, 2, addr, len, mac); 416 wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC", 417 mac, SHA1_MAC_LEN); 418 data->crypto_binding_sent = 1; 419 } 420 421 wpa_hexdump_buf_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 TLV data", 422 buf); 423 424 encr_req = eap_server_tls_encrypt(sm, &data->ssl, buf); 425 wpabuf_free(buf); 426 427 return encr_req; 428 } 429 430 431 static struct wpabuf * eap_peap_build_phase2_term(struct eap_sm *sm, 432 struct eap_peap_data *data, 433 u8 id, int success) 434 { 435 struct wpabuf *encr_req, msgbuf; 436 size_t req_len; 437 struct eap_hdr *hdr; 438 439 req_len = sizeof(*hdr); 440 hdr = os_zalloc(req_len); 441 if (hdr == NULL) 442 return NULL; 443 444 hdr->code = success ? EAP_CODE_SUCCESS : EAP_CODE_FAILURE; 445 hdr->identifier = id; 446 hdr->length = host_to_be16(req_len); 447 448 wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 data", 449 (u8 *) hdr, req_len); 450 451 wpabuf_set(&msgbuf, hdr, req_len); 452 encr_req = eap_server_tls_encrypt(sm, &data->ssl, &msgbuf); 453 os_free(hdr); 454 455 return encr_req; 456 } 457 458 459 static struct wpabuf * eap_peap_buildReq(struct eap_sm *sm, void *priv, u8 id) 460 { 461 struct eap_peap_data *data = priv; 462 463 if (data->ssl.state == FRAG_ACK) { 464 return eap_server_tls_build_ack(id, EAP_TYPE_PEAP, 465 data->peap_version); 466 } 467 468 if (data->ssl.state == WAIT_FRAG_ACK) { 469 return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_PEAP, 470 data->peap_version, id); 471 } 472 473 switch (data->state) { 474 case START: 475 return eap_peap_build_start(sm, data, id); 476 case PHASE1: 477 case PHASE1_ID2: 478 if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) { 479 wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase1 done, " 480 "starting Phase2"); 481 eap_peap_state(data, PHASE2_START); 482 } 483 break; 484 case PHASE2_ID: 485 case PHASE2_METHOD: 486 wpabuf_free(data->ssl.tls_out); 487 data->ssl.tls_out_pos = 0; 488 data->ssl.tls_out = eap_peap_build_phase2_req(sm, data, id); 489 break; 490 #ifdef EAP_SERVER_TNC 491 case PHASE2_SOH: 492 wpabuf_free(data->ssl.tls_out); 493 data->ssl.tls_out_pos = 0; 494 data->ssl.tls_out = eap_peap_build_phase2_soh(sm, data, id); 495 break; 496 #endif /* EAP_SERVER_TNC */ 497 case PHASE2_TLV: 498 wpabuf_free(data->ssl.tls_out); 499 data->ssl.tls_out_pos = 0; 500 data->ssl.tls_out = eap_peap_build_phase2_tlv(sm, data, id); 501 break; 502 case SUCCESS_REQ: 503 wpabuf_free(data->ssl.tls_out); 504 data->ssl.tls_out_pos = 0; 505 data->ssl.tls_out = eap_peap_build_phase2_term(sm, data, id, 506 1); 507 break; 508 case FAILURE_REQ: 509 wpabuf_free(data->ssl.tls_out); 510 data->ssl.tls_out_pos = 0; 511 data->ssl.tls_out = eap_peap_build_phase2_term(sm, data, id, 512 0); 513 break; 514 default: 515 wpa_printf(MSG_DEBUG, "EAP-PEAP: %s - unexpected state %d", 516 __func__, data->state); 517 return NULL; 518 } 519 520 return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_PEAP, 521 data->peap_version, id); 522 } 523 524 525 static Boolean eap_peap_check(struct eap_sm *sm, void *priv, 526 struct wpabuf *respData) 527 { 528 const u8 *pos; 529 size_t len; 530 531 pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PEAP, respData, &len); 532 if (pos == NULL || len < 1) { 533 wpa_printf(MSG_INFO, "EAP-PEAP: Invalid frame"); 534 return TRUE; 535 } 536 537 return FALSE; 538 } 539 540 541 static int eap_peap_phase2_init(struct eap_sm *sm, struct eap_peap_data *data, 542 int vendor, EapType eap_type) 543 { 544 if (data->phase2_priv && data->phase2_method) { 545 data->phase2_method->reset(sm, data->phase2_priv); 546 data->phase2_method = NULL; 547 data->phase2_priv = NULL; 548 } 549 data->phase2_method = eap_server_get_eap_method(vendor, eap_type); 550 if (!data->phase2_method) 551 return -1; 552 553 sm->init_phase2 = 1; 554 data->phase2_priv = data->phase2_method->init(sm); 555 sm->init_phase2 = 0; 556 return 0; 557 } 558 559 560 static int eap_tlv_validate_cryptobinding(struct eap_sm *sm, 561 struct eap_peap_data *data, 562 const u8 *crypto_tlv, 563 size_t crypto_tlv_len) 564 { 565 u8 buf[61], mac[SHA1_MAC_LEN]; 566 const u8 *pos; 567 568 if (crypto_tlv_len != 4 + 56) { 569 wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid cryptobinding TLV " 570 "length %d", (int) crypto_tlv_len); 571 return -1; 572 } 573 574 pos = crypto_tlv; 575 pos += 4; /* TLV header */ 576 if (pos[1] != data->peap_version) { 577 wpa_printf(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV Version " 578 "mismatch (was %d; expected %d)", 579 pos[1], data->peap_version); 580 return -1; 581 } 582 583 if (pos[3] != 1) { 584 wpa_printf(MSG_DEBUG, "EAP-PEAP: Unexpected Cryptobinding TLV " 585 "SubType %d", pos[3]); 586 return -1; 587 } 588 pos += 4; 589 pos += 32; /* Nonce */ 590 591 /* Compound_MAC: HMAC-SHA1-160(cryptobinding TLV | EAP type) */ 592 os_memcpy(buf, crypto_tlv, 60); 593 os_memset(buf + 4 + 4 + 32, 0, 20); /* Compound_MAC */ 594 buf[60] = EAP_TYPE_PEAP; 595 hmac_sha1(data->cmk, 20, buf, sizeof(buf), mac); 596 597 if (os_memcmp_const(mac, pos, SHA1_MAC_LEN) != 0) { 598 wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid Compound_MAC in " 599 "cryptobinding TLV"); 600 wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK", data->cmk, 20); 601 wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Cryptobinding seed data", 602 buf, 61); 603 return -1; 604 } 605 606 wpa_printf(MSG_DEBUG, "EAP-PEAP: Valid cryptobinding TLV received"); 607 608 return 0; 609 } 610 611 612 static void eap_peap_process_phase2_tlv(struct eap_sm *sm, 613 struct eap_peap_data *data, 614 struct wpabuf *in_data) 615 { 616 const u8 *pos; 617 size_t left; 618 const u8 *result_tlv = NULL, *crypto_tlv = NULL; 619 size_t result_tlv_len = 0, crypto_tlv_len = 0; 620 int tlv_type, mandatory, tlv_len; 621 622 pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TLV, in_data, &left); 623 if (pos == NULL) { 624 wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid EAP-TLV header"); 625 return; 626 } 627 628 /* Parse TLVs */ 629 wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Received TLVs", pos, left); 630 while (left >= 4) { 631 mandatory = !!(pos[0] & 0x80); 632 tlv_type = pos[0] & 0x3f; 633 tlv_type = (tlv_type << 8) | pos[1]; 634 tlv_len = ((int) pos[2] << 8) | pos[3]; 635 pos += 4; 636 left -= 4; 637 if ((size_t) tlv_len > left) { 638 wpa_printf(MSG_DEBUG, "EAP-PEAP: TLV underrun " 639 "(tlv_len=%d left=%lu)", tlv_len, 640 (unsigned long) left); 641 eap_peap_state(data, FAILURE); 642 return; 643 } 644 switch (tlv_type) { 645 case EAP_TLV_RESULT_TLV: 646 result_tlv = pos; 647 result_tlv_len = tlv_len; 648 break; 649 case EAP_TLV_CRYPTO_BINDING_TLV: 650 crypto_tlv = pos; 651 crypto_tlv_len = tlv_len; 652 break; 653 default: 654 wpa_printf(MSG_DEBUG, "EAP-PEAP: Unsupported TLV Type " 655 "%d%s", tlv_type, 656 mandatory ? " (mandatory)" : ""); 657 if (mandatory) { 658 eap_peap_state(data, FAILURE); 659 return; 660 } 661 /* Ignore this TLV, but process other TLVs */ 662 break; 663 } 664 665 pos += tlv_len; 666 left -= tlv_len; 667 } 668 if (left) { 669 wpa_printf(MSG_DEBUG, "EAP-PEAP: Last TLV too short in " 670 "Request (left=%lu)", (unsigned long) left); 671 eap_peap_state(data, FAILURE); 672 return; 673 } 674 675 /* Process supported TLVs */ 676 if (crypto_tlv && data->crypto_binding_sent) { 677 wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV", 678 crypto_tlv, crypto_tlv_len); 679 if (eap_tlv_validate_cryptobinding(sm, data, crypto_tlv - 4, 680 crypto_tlv_len + 4) < 0) { 681 eap_peap_state(data, FAILURE); 682 return; 683 } 684 data->crypto_binding_used = 1; 685 } else if (!crypto_tlv && data->crypto_binding_sent && 686 data->crypto_binding == REQUIRE_BINDING) { 687 wpa_printf(MSG_DEBUG, "EAP-PEAP: No cryptobinding TLV"); 688 eap_peap_state(data, FAILURE); 689 return; 690 } 691 692 if (result_tlv) { 693 int status; 694 const char *requested; 695 696 wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Result TLV", 697 result_tlv, result_tlv_len); 698 if (result_tlv_len < 2) { 699 wpa_printf(MSG_INFO, "EAP-PEAP: Too short Result TLV " 700 "(len=%lu)", 701 (unsigned long) result_tlv_len); 702 eap_peap_state(data, FAILURE); 703 return; 704 } 705 requested = data->tlv_request == TLV_REQ_SUCCESS ? "Success" : 706 "Failure"; 707 status = WPA_GET_BE16(result_tlv); 708 if (status == EAP_TLV_RESULT_SUCCESS) { 709 wpa_printf(MSG_INFO, "EAP-PEAP: TLV Result - Success " 710 "- requested %s", requested); 711 if (data->tlv_request == TLV_REQ_SUCCESS) 712 eap_peap_state(data, SUCCESS); 713 else 714 eap_peap_state(data, FAILURE); 715 716 } else if (status == EAP_TLV_RESULT_FAILURE) { 717 wpa_printf(MSG_INFO, "EAP-PEAP: TLV Result - Failure " 718 "- requested %s", requested); 719 eap_peap_state(data, FAILURE); 720 } else { 721 wpa_printf(MSG_INFO, "EAP-PEAP: Unknown TLV Result " 722 "Status %d", status); 723 eap_peap_state(data, FAILURE); 724 } 725 } 726 } 727 728 729 #ifdef EAP_SERVER_TNC 730 static void eap_peap_process_phase2_soh(struct eap_sm *sm, 731 struct eap_peap_data *data, 732 struct wpabuf *in_data) 733 { 734 const u8 *pos, *vpos; 735 size_t left; 736 const u8 *soh_tlv = NULL; 737 size_t soh_tlv_len = 0; 738 int tlv_type, mandatory, tlv_len, vtlv_len; 739 u32 next_type; 740 u32 vendor_id; 741 742 pos = eap_hdr_validate(EAP_VENDOR_MICROSOFT, 0x21, in_data, &left); 743 if (pos == NULL) { 744 wpa_printf(MSG_DEBUG, "EAP-PEAP: Not a valid SoH EAP " 745 "Extensions Method header - skip TNC"); 746 goto auth_method; 747 } 748 749 /* Parse TLVs */ 750 wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Received TLVs (SoH)", pos, left); 751 while (left >= 4) { 752 mandatory = !!(pos[0] & 0x80); 753 tlv_type = pos[0] & 0x3f; 754 tlv_type = (tlv_type << 8) | pos[1]; 755 tlv_len = ((int) pos[2] << 8) | pos[3]; 756 pos += 4; 757 left -= 4; 758 if ((size_t) tlv_len > left) { 759 wpa_printf(MSG_DEBUG, "EAP-PEAP: TLV underrun " 760 "(tlv_len=%d left=%lu)", tlv_len, 761 (unsigned long) left); 762 eap_peap_state(data, FAILURE); 763 return; 764 } 765 switch (tlv_type) { 766 case EAP_TLV_VENDOR_SPECIFIC_TLV: 767 if (tlv_len < 4) { 768 wpa_printf(MSG_DEBUG, "EAP-PEAP: Too short " 769 "vendor specific TLV (len=%d)", 770 (int) tlv_len); 771 eap_peap_state(data, FAILURE); 772 return; 773 } 774 775 vendor_id = WPA_GET_BE32(pos); 776 if (vendor_id != EAP_VENDOR_MICROSOFT) { 777 if (mandatory) { 778 eap_peap_state(data, FAILURE); 779 return; 780 } 781 break; 782 } 783 784 vpos = pos + 4; 785 mandatory = !!(vpos[0] & 0x80); 786 tlv_type = vpos[0] & 0x3f; 787 tlv_type = (tlv_type << 8) | vpos[1]; 788 vtlv_len = ((int) vpos[2] << 8) | vpos[3]; 789 vpos += 4; 790 if (vpos + vtlv_len > pos + left) { 791 wpa_printf(MSG_DEBUG, "EAP-PEAP: Vendor TLV " 792 "underrun"); 793 eap_peap_state(data, FAILURE); 794 return; 795 } 796 797 if (tlv_type == 1) { 798 soh_tlv = vpos; 799 soh_tlv_len = vtlv_len; 800 break; 801 } 802 803 wpa_printf(MSG_DEBUG, "EAP-PEAP: Unsupported MS-TLV " 804 "Type %d%s", tlv_type, 805 mandatory ? " (mandatory)" : ""); 806 if (mandatory) { 807 eap_peap_state(data, FAILURE); 808 return; 809 } 810 /* Ignore this TLV, but process other TLVs */ 811 break; 812 default: 813 wpa_printf(MSG_DEBUG, "EAP-PEAP: Unsupported TLV Type " 814 "%d%s", tlv_type, 815 mandatory ? " (mandatory)" : ""); 816 if (mandatory) { 817 eap_peap_state(data, FAILURE); 818 return; 819 } 820 /* Ignore this TLV, but process other TLVs */ 821 break; 822 } 823 824 pos += tlv_len; 825 left -= tlv_len; 826 } 827 if (left) { 828 wpa_printf(MSG_DEBUG, "EAP-PEAP: Last TLV too short in " 829 "Request (left=%lu)", (unsigned long) left); 830 eap_peap_state(data, FAILURE); 831 return; 832 } 833 834 /* Process supported TLVs */ 835 if (soh_tlv) { 836 int failure = 0; 837 wpabuf_free(data->soh_response); 838 data->soh_response = tncs_process_soh(soh_tlv, soh_tlv_len, 839 &failure); 840 if (failure) { 841 eap_peap_state(data, FAILURE); 842 return; 843 } 844 } else { 845 wpa_printf(MSG_DEBUG, "EAP-PEAP: No SoH TLV received"); 846 eap_peap_state(data, FAILURE); 847 return; 848 } 849 850 auth_method: 851 eap_peap_state(data, PHASE2_METHOD); 852 next_type = sm->user->methods[0].method; 853 sm->user_eap_method_index = 1; 854 wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP vendor %d type %d", 855 sm->user->methods[0].vendor, next_type); 856 eap_peap_phase2_init(sm, data, sm->user->methods[0].vendor, next_type); 857 } 858 #endif /* EAP_SERVER_TNC */ 859 860 861 static void eap_peap_process_phase2_response(struct eap_sm *sm, 862 struct eap_peap_data *data, 863 struct wpabuf *in_data) 864 { 865 int next_vendor = EAP_VENDOR_IETF; 866 u32 next_type = EAP_TYPE_NONE; 867 const struct eap_hdr *hdr; 868 const u8 *pos; 869 size_t left; 870 871 if (data->state == PHASE2_TLV) { 872 eap_peap_process_phase2_tlv(sm, data, in_data); 873 return; 874 } 875 876 #ifdef EAP_SERVER_TNC 877 if (data->state == PHASE2_SOH) { 878 eap_peap_process_phase2_soh(sm, data, in_data); 879 return; 880 } 881 #endif /* EAP_SERVER_TNC */ 882 883 if (data->phase2_priv == NULL) { 884 wpa_printf(MSG_DEBUG, "EAP-PEAP: %s - Phase2 not " 885 "initialized?!", __func__); 886 return; 887 } 888 889 hdr = wpabuf_head(in_data); 890 pos = (const u8 *) (hdr + 1); 891 892 if (wpabuf_len(in_data) > sizeof(*hdr) && *pos == EAP_TYPE_NAK) { 893 left = wpabuf_len(in_data) - sizeof(*hdr); 894 wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Phase2 type Nak'ed; " 895 "allowed types", pos + 1, left - 1); 896 eap_sm_process_nak(sm, pos + 1, left - 1); 897 if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS && 898 (sm->user->methods[sm->user_eap_method_index].vendor != 899 EAP_VENDOR_IETF || 900 sm->user->methods[sm->user_eap_method_index].method != 901 EAP_TYPE_NONE)) { 902 next_vendor = sm->user->methods[ 903 sm->user_eap_method_index].vendor; 904 next_type = sm->user->methods[ 905 sm->user_eap_method_index++].method; 906 wpa_printf(MSG_DEBUG, 907 "EAP-PEAP: try EAP vendor %d type 0x%x", 908 next_vendor, next_type); 909 } else { 910 eap_peap_req_failure(sm, data); 911 next_vendor = EAP_VENDOR_IETF; 912 next_type = EAP_TYPE_NONE; 913 } 914 eap_peap_phase2_init(sm, data, next_vendor, next_type); 915 return; 916 } 917 918 if (data->phase2_method->check(sm, data->phase2_priv, in_data)) { 919 wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 check() asked to " 920 "ignore the packet"); 921 return; 922 } 923 924 data->phase2_method->process(sm, data->phase2_priv, in_data); 925 926 if (sm->method_pending == METHOD_PENDING_WAIT) { 927 wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 method is in " 928 "pending wait state - save decrypted response"); 929 wpabuf_free(data->pending_phase2_resp); 930 data->pending_phase2_resp = wpabuf_dup(in_data); 931 } 932 933 if (!data->phase2_method->isDone(sm, data->phase2_priv)) 934 return; 935 936 if (!data->phase2_method->isSuccess(sm, data->phase2_priv)) { 937 wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 method failed"); 938 eap_peap_req_failure(sm, data); 939 next_vendor = EAP_VENDOR_IETF; 940 next_type = EAP_TYPE_NONE; 941 eap_peap_phase2_init(sm, data, next_vendor, next_type); 942 return; 943 } 944 945 os_free(data->phase2_key); 946 if (data->phase2_method->getKey) { 947 data->phase2_key = data->phase2_method->getKey( 948 sm, data->phase2_priv, &data->phase2_key_len); 949 if (data->phase2_key == NULL) { 950 wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 getKey " 951 "failed"); 952 eap_peap_req_failure(sm, data); 953 eap_peap_phase2_init(sm, data, EAP_VENDOR_IETF, 954 EAP_TYPE_NONE); 955 return; 956 } 957 } 958 959 switch (data->state) { 960 case PHASE1_ID2: 961 case PHASE2_ID: 962 case PHASE2_SOH: 963 if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) { 964 wpa_hexdump_ascii(MSG_DEBUG, "EAP_PEAP: Phase2 " 965 "Identity not found in the user " 966 "database", 967 sm->identity, sm->identity_len); 968 eap_peap_req_failure(sm, data); 969 next_vendor = EAP_VENDOR_IETF; 970 next_type = EAP_TYPE_NONE; 971 break; 972 } 973 974 #ifdef EAP_SERVER_TNC 975 if (data->state != PHASE2_SOH && sm->tnc && 976 data->peap_version == 0) { 977 eap_peap_state(data, PHASE2_SOH); 978 wpa_printf(MSG_DEBUG, "EAP-PEAP: Try to initialize " 979 "TNC (NAP SOH)"); 980 next_vendor = EAP_VENDOR_IETF; 981 next_type = EAP_TYPE_NONE; 982 break; 983 } 984 #endif /* EAP_SERVER_TNC */ 985 986 eap_peap_state(data, PHASE2_METHOD); 987 next_vendor = sm->user->methods[0].vendor; 988 next_type = sm->user->methods[0].method; 989 sm->user_eap_method_index = 1; 990 wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP vendor %d type 0x%x", 991 next_vendor, next_type); 992 break; 993 case PHASE2_METHOD: 994 eap_peap_req_success(sm, data); 995 next_vendor = EAP_VENDOR_IETF; 996 next_type = EAP_TYPE_NONE; 997 break; 998 case FAILURE: 999 break; 1000 default: 1001 wpa_printf(MSG_DEBUG, "EAP-PEAP: %s - unexpected state %d", 1002 __func__, data->state); 1003 break; 1004 } 1005 1006 eap_peap_phase2_init(sm, data, next_vendor, next_type); 1007 } 1008 1009 1010 static void eap_peap_process_phase2(struct eap_sm *sm, 1011 struct eap_peap_data *data, 1012 const struct wpabuf *respData, 1013 struct wpabuf *in_buf) 1014 { 1015 struct wpabuf *in_decrypted; 1016 const struct eap_hdr *hdr; 1017 size_t len; 1018 1019 wpa_printf(MSG_DEBUG, "EAP-PEAP: received %lu bytes encrypted data for" 1020 " Phase 2", (unsigned long) wpabuf_len(in_buf)); 1021 1022 if (data->pending_phase2_resp) { 1023 wpa_printf(MSG_DEBUG, "EAP-PEAP: Pending Phase 2 response - " 1024 "skip decryption and use old data"); 1025 eap_peap_process_phase2_response(sm, data, 1026 data->pending_phase2_resp); 1027 wpabuf_free(data->pending_phase2_resp); 1028 data->pending_phase2_resp = NULL; 1029 return; 1030 } 1031 1032 in_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn, 1033 in_buf); 1034 if (in_decrypted == NULL) { 1035 wpa_printf(MSG_INFO, "EAP-PEAP: Failed to decrypt Phase 2 " 1036 "data"); 1037 eap_peap_state(data, FAILURE); 1038 return; 1039 } 1040 1041 wpa_hexdump_buf_key(MSG_DEBUG, "EAP-PEAP: Decrypted Phase 2 EAP", 1042 in_decrypted); 1043 1044 if (data->peap_version == 0 && data->state != PHASE2_TLV) { 1045 const struct eap_hdr *resp; 1046 struct eap_hdr *nhdr; 1047 struct wpabuf *nbuf = 1048 wpabuf_alloc(sizeof(struct eap_hdr) + 1049 wpabuf_len(in_decrypted)); 1050 if (nbuf == NULL) { 1051 wpabuf_free(in_decrypted); 1052 return; 1053 } 1054 1055 resp = wpabuf_head(respData); 1056 nhdr = wpabuf_put(nbuf, sizeof(*nhdr)); 1057 nhdr->code = resp->code; 1058 nhdr->identifier = resp->identifier; 1059 nhdr->length = host_to_be16(sizeof(struct eap_hdr) + 1060 wpabuf_len(in_decrypted)); 1061 wpabuf_put_buf(nbuf, in_decrypted); 1062 wpabuf_free(in_decrypted); 1063 1064 in_decrypted = nbuf; 1065 } 1066 1067 hdr = wpabuf_head(in_decrypted); 1068 if (wpabuf_len(in_decrypted) < (int) sizeof(*hdr)) { 1069 wpa_printf(MSG_INFO, "EAP-PEAP: Too short Phase 2 " 1070 "EAP frame (len=%lu)", 1071 (unsigned long) wpabuf_len(in_decrypted)); 1072 wpabuf_free(in_decrypted); 1073 eap_peap_req_failure(sm, data); 1074 return; 1075 } 1076 len = be_to_host16(hdr->length); 1077 if (len > wpabuf_len(in_decrypted)) { 1078 wpa_printf(MSG_INFO, "EAP-PEAP: Length mismatch in " 1079 "Phase 2 EAP frame (len=%lu hdr->length=%lu)", 1080 (unsigned long) wpabuf_len(in_decrypted), 1081 (unsigned long) len); 1082 wpabuf_free(in_decrypted); 1083 eap_peap_req_failure(sm, data); 1084 return; 1085 } 1086 wpa_printf(MSG_DEBUG, "EAP-PEAP: received Phase 2: code=%d " 1087 "identifier=%d length=%lu", hdr->code, hdr->identifier, 1088 (unsigned long) len); 1089 switch (hdr->code) { 1090 case EAP_CODE_RESPONSE: 1091 eap_peap_process_phase2_response(sm, data, in_decrypted); 1092 break; 1093 case EAP_CODE_SUCCESS: 1094 wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Success"); 1095 if (data->state == SUCCESS_REQ) { 1096 eap_peap_state(data, SUCCESS); 1097 } 1098 break; 1099 case EAP_CODE_FAILURE: 1100 wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Failure"); 1101 eap_peap_state(data, FAILURE); 1102 break; 1103 default: 1104 wpa_printf(MSG_INFO, "EAP-PEAP: Unexpected code=%d in " 1105 "Phase 2 EAP header", hdr->code); 1106 break; 1107 } 1108 1109 wpabuf_free(in_decrypted); 1110 } 1111 1112 1113 static int eap_peap_process_version(struct eap_sm *sm, void *priv, 1114 int peer_version) 1115 { 1116 struct eap_peap_data *data = priv; 1117 1118 data->recv_version = peer_version; 1119 if (data->force_version >= 0 && peer_version != data->force_version) { 1120 wpa_printf(MSG_INFO, "EAP-PEAP: peer did not select the forced" 1121 " version (forced=%d peer=%d) - reject", 1122 data->force_version, peer_version); 1123 return -1; 1124 } 1125 if (peer_version < data->peap_version) { 1126 wpa_printf(MSG_DEBUG, "EAP-PEAP: peer ver=%d, own ver=%d; " 1127 "use version %d", 1128 peer_version, data->peap_version, peer_version); 1129 data->peap_version = peer_version; 1130 } 1131 1132 return 0; 1133 } 1134 1135 1136 static void eap_peap_process_msg(struct eap_sm *sm, void *priv, 1137 const struct wpabuf *respData) 1138 { 1139 struct eap_peap_data *data = priv; 1140 1141 switch (data->state) { 1142 case PHASE1: 1143 if (eap_server_tls_phase1(sm, &data->ssl) < 0) { 1144 eap_peap_state(data, FAILURE); 1145 break; 1146 } 1147 break; 1148 case PHASE2_START: 1149 eap_peap_state(data, PHASE2_ID); 1150 eap_peap_phase2_init(sm, data, EAP_VENDOR_IETF, 1151 EAP_TYPE_IDENTITY); 1152 break; 1153 case PHASE1_ID2: 1154 case PHASE2_ID: 1155 case PHASE2_METHOD: 1156 case PHASE2_SOH: 1157 case PHASE2_TLV: 1158 eap_peap_process_phase2(sm, data, respData, data->ssl.tls_in); 1159 break; 1160 case SUCCESS_REQ: 1161 eap_peap_state(data, SUCCESS); 1162 break; 1163 case FAILURE_REQ: 1164 eap_peap_state(data, FAILURE); 1165 break; 1166 default: 1167 wpa_printf(MSG_DEBUG, "EAP-PEAP: Unexpected state %d in %s", 1168 data->state, __func__); 1169 break; 1170 } 1171 } 1172 1173 1174 static void eap_peap_process(struct eap_sm *sm, void *priv, 1175 struct wpabuf *respData) 1176 { 1177 struct eap_peap_data *data = priv; 1178 if (eap_server_tls_process(sm, &data->ssl, respData, data, 1179 EAP_TYPE_PEAP, eap_peap_process_version, 1180 eap_peap_process_msg) < 0) 1181 eap_peap_state(data, FAILURE); 1182 } 1183 1184 1185 static Boolean eap_peap_isDone(struct eap_sm *sm, void *priv) 1186 { 1187 struct eap_peap_data *data = priv; 1188 return data->state == SUCCESS || data->state == FAILURE; 1189 } 1190 1191 1192 static u8 * eap_peap_getKey(struct eap_sm *sm, void *priv, size_t *len) 1193 { 1194 struct eap_peap_data *data = priv; 1195 u8 *eapKeyData; 1196 1197 if (data->state != SUCCESS) 1198 return NULL; 1199 1200 if (data->crypto_binding_used) { 1201 u8 csk[128]; 1202 /* 1203 * Note: It looks like Microsoft implementation requires null 1204 * termination for this label while the one used for deriving 1205 * IPMK|CMK did not use null termination. 1206 */ 1207 if (peap_prfplus(data->peap_version, data->ipmk, 40, 1208 "Session Key Generating Function", 1209 (u8 *) "\00", 1, csk, sizeof(csk)) < 0) 1210 return NULL; 1211 wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CSK", csk, sizeof(csk)); 1212 eapKeyData = os_malloc(EAP_TLS_KEY_LEN); 1213 if (eapKeyData) { 1214 os_memcpy(eapKeyData, csk, EAP_TLS_KEY_LEN); 1215 *len = EAP_TLS_KEY_LEN; 1216 wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Derived key", 1217 eapKeyData, EAP_TLS_KEY_LEN); 1218 } else { 1219 wpa_printf(MSG_DEBUG, "EAP-PEAP: Failed to derive " 1220 "key"); 1221 } 1222 1223 return eapKeyData; 1224 } 1225 1226 /* TODO: PEAPv1 - different label in some cases */ 1227 eapKeyData = eap_server_tls_derive_key(sm, &data->ssl, 1228 "client EAP encryption", 1229 EAP_TLS_KEY_LEN); 1230 if (eapKeyData) { 1231 *len = EAP_TLS_KEY_LEN; 1232 wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Derived key", 1233 eapKeyData, EAP_TLS_KEY_LEN); 1234 } else { 1235 wpa_printf(MSG_DEBUG, "EAP-PEAP: Failed to derive key"); 1236 } 1237 1238 return eapKeyData; 1239 } 1240 1241 1242 static Boolean eap_peap_isSuccess(struct eap_sm *sm, void *priv) 1243 { 1244 struct eap_peap_data *data = priv; 1245 return data->state == SUCCESS; 1246 } 1247 1248 1249 static u8 * eap_peap_get_session_id(struct eap_sm *sm, void *priv, size_t *len) 1250 { 1251 struct eap_peap_data *data = priv; 1252 1253 if (data->state != SUCCESS) 1254 return NULL; 1255 1256 return eap_server_tls_derive_session_id(sm, &data->ssl, EAP_TYPE_PEAP, 1257 len); 1258 } 1259 1260 1261 int eap_server_peap_register(void) 1262 { 1263 struct eap_method *eap; 1264 int ret; 1265 1266 eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, 1267 EAP_VENDOR_IETF, EAP_TYPE_PEAP, "PEAP"); 1268 if (eap == NULL) 1269 return -1; 1270 1271 eap->init = eap_peap_init; 1272 eap->reset = eap_peap_reset; 1273 eap->buildReq = eap_peap_buildReq; 1274 eap->check = eap_peap_check; 1275 eap->process = eap_peap_process; 1276 eap->isDone = eap_peap_isDone; 1277 eap->getKey = eap_peap_getKey; 1278 eap->isSuccess = eap_peap_isSuccess; 1279 eap->getSessionId = eap_peap_get_session_id; 1280 1281 ret = eap_server_method_register(eap); 1282 if (ret) 1283 eap_server_method_free(eap); 1284 return ret; 1285 } 1286