00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "includes.h"
00025
00026 #include "common.h"
00027 #include "pcsc_funcs.h"
00028 #include "state_machine.h"
00029 #include "crypto/crypto.h"
00030 #include "crypto/tls.h"
00031 #include "common/wpa_ctrl.h"
00032 #include "eap_common/eap_wsc_common.h"
00033 #include "eap_i.h"
00034 #include "eap_config.h"
00035
00036 #define STATE_MACHINE_DATA struct eap_sm
00037 #define STATE_MACHINE_DEBUG_PREFIX "EAP"
00038
00039 #define EAP_MAX_AUTH_ROUNDS 50
00040
00041
00042 static Boolean eap_sm_allowMethod(struct eap_sm *sm, int vendor,
00043 EapType method);
00044 static struct wpabuf * eap_sm_buildNak(struct eap_sm *sm, int id);
00045 static void eap_sm_processIdentity(struct eap_sm *sm,
00046 const struct wpabuf *req);
00047 static void eap_sm_processNotify(struct eap_sm *sm, const struct wpabuf *req);
00048 static struct wpabuf * eap_sm_buildNotify(int id);
00049 static void eap_sm_parseEapReq(struct eap_sm *sm, const struct wpabuf *req);
00050 #if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
00051 static const char * eap_sm_method_state_txt(EapMethodState state);
00052 static const char * eap_sm_decision_txt(EapDecision decision);
00053 #endif
00054
00055
00056
00057 static Boolean eapol_get_bool(struct eap_sm *sm, enum eapol_bool_var var)
00058 {
00059 return sm->eapol_cb->get_bool(sm->eapol_ctx, var);
00060 }
00061
00062
00063 static void eapol_set_bool(struct eap_sm *sm, enum eapol_bool_var var,
00064 Boolean value)
00065 {
00066 sm->eapol_cb->set_bool(sm->eapol_ctx, var, value);
00067 }
00068
00069
00070 static unsigned int eapol_get_int(struct eap_sm *sm, enum eapol_int_var var)
00071 {
00072 return sm->eapol_cb->get_int(sm->eapol_ctx, var);
00073 }
00074
00075
00076 static void eapol_set_int(struct eap_sm *sm, enum eapol_int_var var,
00077 unsigned int value)
00078 {
00079 sm->eapol_cb->set_int(sm->eapol_ctx, var, value);
00080 }
00081
00082
00083 static struct wpabuf * eapol_get_eapReqData(struct eap_sm *sm)
00084 {
00085 return sm->eapol_cb->get_eapReqData(sm->eapol_ctx);
00086 }
00087
00088
00089 static void eap_deinit_prev_method(struct eap_sm *sm, const char *txt)
00090 {
00091 if (sm->m == NULL || sm->eap_method_priv == NULL)
00092 return;
00093
00094 wpa_printf(MSG_DEBUG, "EAP: deinitialize previously used EAP method "
00095 "(%d, %s) at %s", sm->selectedMethod, sm->m->name, txt);
00096 sm->m->deinit(sm, sm->eap_method_priv);
00097 sm->eap_method_priv = NULL;
00098 sm->m = NULL;
00099 }
00100
00101
00109 int eap_allowed_method(struct eap_sm *sm, int vendor, u32 method)
00110 {
00111 struct eap_peer_config *config = eap_get_config(sm);
00112 int i;
00113 struct eap_method_type *m;
00114
00115 if (config == NULL || config->eap_methods == NULL)
00116 return 1;
00117
00118 m = config->eap_methods;
00119 for (i = 0; m[i].vendor != EAP_VENDOR_IETF ||
00120 m[i].method != EAP_TYPE_NONE; i++) {
00121 if (m[i].vendor == vendor && m[i].method == method)
00122 return 1;
00123 }
00124 return 0;
00125 }
00126
00127
00128
00129
00130
00131
00132
00133 SM_STATE(EAP, INITIALIZE)
00134 {
00135 SM_ENTRY(EAP, INITIALIZE);
00136 if (sm->fast_reauth && sm->m && sm->m->has_reauth_data &&
00137 sm->m->has_reauth_data(sm, sm->eap_method_priv) &&
00138 !sm->prev_failure) {
00139 wpa_printf(MSG_DEBUG, "EAP: maintaining EAP method data for "
00140 "fast reauthentication");
00141 sm->m->deinit_for_reauth(sm, sm->eap_method_priv);
00142 } else {
00143 eap_deinit_prev_method(sm, "INITIALIZE");
00144 }
00145 sm->selectedMethod = EAP_TYPE_NONE;
00146 sm->methodState = METHOD_NONE;
00147 sm->allowNotifications = TRUE;
00148 sm->decision = DECISION_FAIL;
00149 eapol_set_int(sm, EAPOL_idleWhile, sm->ClientTimeout);
00150 eapol_set_bool(sm, EAPOL_eapSuccess, FALSE);
00151 eapol_set_bool(sm, EAPOL_eapFail, FALSE);
00152 os_free(sm->eapKeyData);
00153 sm->eapKeyData = NULL;
00154 sm->eapKeyAvailable = FALSE;
00155 eapol_set_bool(sm, EAPOL_eapRestart, FALSE);
00156 sm->lastId = -1;
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166 eapol_set_bool(sm, EAPOL_eapResp, FALSE);
00167 eapol_set_bool(sm, EAPOL_eapNoResp, FALSE);
00168 sm->num_rounds = 0;
00169 sm->prev_failure = 0;
00170 }
00171
00172
00173
00174
00175
00176
00177
00178 SM_STATE(EAP, DISABLED)
00179 {
00180 SM_ENTRY(EAP, DISABLED);
00181 sm->num_rounds = 0;
00182 }
00183
00184
00185
00186
00187
00188
00189
00190 SM_STATE(EAP, IDLE)
00191 {
00192 SM_ENTRY(EAP, IDLE);
00193 }
00194
00195
00196
00197
00198
00199
00200 SM_STATE(EAP, RECEIVED)
00201 {
00202 const struct wpabuf *eapReqData;
00203
00204 SM_ENTRY(EAP, RECEIVED);
00205 eapReqData = eapol_get_eapReqData(sm);
00206
00207 eap_sm_parseEapReq(sm, eapReqData);
00208 sm->num_rounds++;
00209 }
00210
00211
00212
00213
00214
00215
00216 SM_STATE(EAP, GET_METHOD)
00217 {
00218 int reinit;
00219 EapType method;
00220
00221 SM_ENTRY(EAP, GET_METHOD);
00222
00223 if (sm->reqMethod == EAP_TYPE_EXPANDED)
00224 method = sm->reqVendorMethod;
00225 else
00226 method = sm->reqMethod;
00227
00228 if (!eap_sm_allowMethod(sm, sm->reqVendor, method)) {
00229 wpa_printf(MSG_DEBUG, "EAP: vendor %u method %u not allowed",
00230 sm->reqVendor, method);
00231 wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD
00232 "vendor=%u method=%u -> NAK",
00233 sm->reqVendor, method);
00234 goto nak;
00235 }
00236
00237 wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD
00238 "vendor=%u method=%u", sm->reqVendor, method);
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248 if (sm->fast_reauth &&
00249 sm->m && sm->m->vendor == sm->reqVendor &&
00250 sm->m->method == method &&
00251 sm->m->has_reauth_data &&
00252 sm->m->has_reauth_data(sm, sm->eap_method_priv)) {
00253 wpa_printf(MSG_DEBUG, "EAP: Using previous method data"
00254 " for fast re-authentication");
00255 reinit = 1;
00256 } else {
00257 eap_deinit_prev_method(sm, "GET_METHOD");
00258 reinit = 0;
00259 }
00260
00261 sm->selectedMethod = sm->reqMethod;
00262 if (sm->m == NULL)
00263 sm->m = eap_peer_get_eap_method(sm->reqVendor, method);
00264 if (!sm->m) {
00265 wpa_printf(MSG_DEBUG, "EAP: Could not find selected method: "
00266 "vendor %d method %d",
00267 sm->reqVendor, method);
00268 goto nak;
00269 }
00270
00271 wpa_printf(MSG_DEBUG, "EAP: Initialize selected EAP method: "
00272 "vendor %u method %u (%s)",
00273 sm->reqVendor, method, sm->m->name);
00274 if (reinit)
00275 sm->eap_method_priv = sm->m->init_for_reauth(
00276 sm, sm->eap_method_priv);
00277 else
00278 sm->eap_method_priv = sm->m->init(sm);
00279
00280 if (sm->eap_method_priv == NULL) {
00281 struct eap_peer_config *config = eap_get_config(sm);
00282 wpa_msg(sm->msg_ctx, MSG_INFO,
00283 "EAP: Failed to initialize EAP method: vendor %u "
00284 "method %u (%s)",
00285 sm->reqVendor, method, sm->m->name);
00286 sm->m = NULL;
00287 sm->methodState = METHOD_NONE;
00288 sm->selectedMethod = EAP_TYPE_NONE;
00289 if (sm->reqMethod == EAP_TYPE_TLS && config &&
00290 (config->pending_req_pin ||
00291 config->pending_req_passphrase)) {
00292
00293
00294
00295
00296
00297 wpa_printf(MSG_DEBUG, "EAP: Pending PIN/passphrase "
00298 "request - skip Nak");
00299 return;
00300 }
00301
00302 goto nak;
00303 }
00304
00305 sm->methodState = METHOD_INIT;
00306 wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_METHOD
00307 "EAP vendor %u method %u (%s) selected",
00308 sm->reqVendor, method, sm->m->name);
00309 return;
00310
00311 nak:
00312 wpabuf_free(sm->eapRespData);
00313 sm->eapRespData = NULL;
00314 sm->eapRespData = eap_sm_buildNak(sm, sm->reqId);
00315 }
00316
00317
00318
00319
00320
00321
00322 SM_STATE(EAP, METHOD)
00323 {
00324 struct wpabuf *eapReqData;
00325 struct eap_method_ret ret;
00326
00327 SM_ENTRY(EAP, METHOD);
00328 if (sm->m == NULL) {
00329 wpa_printf(MSG_WARNING, "EAP::METHOD - method not selected");
00330 return;
00331 }
00332
00333 eapReqData = eapol_get_eapReqData(sm);
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349 os_memset(&ret, 0, sizeof(ret));
00350 ret.ignore = sm->ignore;
00351 ret.methodState = sm->methodState;
00352 ret.decision = sm->decision;
00353 ret.allowNotifications = sm->allowNotifications;
00354 wpabuf_free(sm->eapRespData);
00355 sm->eapRespData = NULL;
00356 sm->eapRespData = sm->m->process(sm, sm->eap_method_priv, &ret,
00357 eapReqData);
00358 wpa_printf(MSG_DEBUG, "EAP: method process -> ignore=%s "
00359 "methodState=%s decision=%s",
00360 ret.ignore ? "TRUE" : "FALSE",
00361 eap_sm_method_state_txt(ret.methodState),
00362 eap_sm_decision_txt(ret.decision));
00363
00364 sm->ignore = ret.ignore;
00365 if (sm->ignore)
00366 return;
00367 sm->methodState = ret.methodState;
00368 sm->decision = ret.decision;
00369 sm->allowNotifications = ret.allowNotifications;
00370
00371 if (sm->m->isKeyAvailable && sm->m->getKey &&
00372 sm->m->isKeyAvailable(sm, sm->eap_method_priv)) {
00373 os_free(sm->eapKeyData);
00374 sm->eapKeyData = sm->m->getKey(sm, sm->eap_method_priv,
00375 &sm->eapKeyDataLen);
00376 }
00377 }
00378
00379
00380
00381
00382
00383
00384 SM_STATE(EAP, SEND_RESPONSE)
00385 {
00386 SM_ENTRY(EAP, SEND_RESPONSE);
00387 wpabuf_free(sm->lastRespData);
00388 if (sm->eapRespData) {
00389 if (sm->workaround)
00390 os_memcpy(sm->last_md5, sm->req_md5, 16);
00391 sm->lastId = sm->reqId;
00392 sm->lastRespData = wpabuf_dup(sm->eapRespData);
00393 eapol_set_bool(sm, EAPOL_eapResp, TRUE);
00394 } else
00395 sm->lastRespData = NULL;
00396 eapol_set_bool(sm, EAPOL_eapReq, FALSE);
00397 eapol_set_int(sm, EAPOL_idleWhile, sm->ClientTimeout);
00398 }
00399
00400
00401
00402
00403
00404
00405 SM_STATE(EAP, DISCARD)
00406 {
00407 SM_ENTRY(EAP, DISCARD);
00408 eapol_set_bool(sm, EAPOL_eapReq, FALSE);
00409 eapol_set_bool(sm, EAPOL_eapNoResp, TRUE);
00410 }
00411
00412
00413
00414
00415
00416 SM_STATE(EAP, IDENTITY)
00417 {
00418 const struct wpabuf *eapReqData;
00419
00420 SM_ENTRY(EAP, IDENTITY);
00421 eapReqData = eapol_get_eapReqData(sm);
00422 eap_sm_processIdentity(sm, eapReqData);
00423 wpabuf_free(sm->eapRespData);
00424 sm->eapRespData = NULL;
00425 sm->eapRespData = eap_sm_buildIdentity(sm, sm->reqId, 0);
00426 }
00427
00428
00429
00430
00431
00432 SM_STATE(EAP, NOTIFICATION)
00433 {
00434 const struct wpabuf *eapReqData;
00435
00436 SM_ENTRY(EAP, NOTIFICATION);
00437 eapReqData = eapol_get_eapReqData(sm);
00438 eap_sm_processNotify(sm, eapReqData);
00439 wpabuf_free(sm->eapRespData);
00440 sm->eapRespData = NULL;
00441 sm->eapRespData = eap_sm_buildNotify(sm->reqId);
00442 }
00443
00444
00445
00446
00447
00448 SM_STATE(EAP, RETRANSMIT)
00449 {
00450 SM_ENTRY(EAP, RETRANSMIT);
00451 wpabuf_free(sm->eapRespData);
00452 if (sm->lastRespData)
00453 sm->eapRespData = wpabuf_dup(sm->lastRespData);
00454 else
00455 sm->eapRespData = NULL;
00456 }
00457
00458
00459
00460
00461
00462
00463
00464 SM_STATE(EAP, SUCCESS)
00465 {
00466 SM_ENTRY(EAP, SUCCESS);
00467 if (sm->eapKeyData != NULL)
00468 sm->eapKeyAvailable = TRUE;
00469 eapol_set_bool(sm, EAPOL_eapSuccess, TRUE);
00470
00471
00472
00473
00474
00475
00476 eapol_set_bool(sm, EAPOL_eapReq, FALSE);
00477
00478
00479
00480
00481
00482
00483
00484 eapol_set_bool(sm, EAPOL_eapNoResp, TRUE);
00485
00486 wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS
00487 "EAP authentication completed successfully");
00488 }
00489
00490
00491
00492
00493
00494
00495 SM_STATE(EAP, FAILURE)
00496 {
00497 SM_ENTRY(EAP, FAILURE);
00498 eapol_set_bool(sm, EAPOL_eapFail, TRUE);
00499
00500
00501
00502
00503
00504
00505 eapol_set_bool(sm, EAPOL_eapReq, FALSE);
00506
00507
00508
00509
00510
00511
00512 eapol_set_bool(sm, EAPOL_eapNoResp, TRUE);
00513
00514 wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE
00515 "EAP authentication failed");
00516
00517 sm->prev_failure = 1;
00518 }
00519
00520
00521 static int eap_success_workaround(struct eap_sm *sm, int reqId, int lastId)
00522 {
00523
00524
00525
00526
00527
00528
00529
00530
00531
00532
00533 if (sm->workaround && (reqId == ((lastId + 1) & 0xff) ||
00534 reqId == ((lastId + 2) & 0xff))) {
00535 wpa_printf(MSG_DEBUG, "EAP: Workaround for unexpected "
00536 "identifier field in EAP Success: "
00537 "reqId=%d lastId=%d (these are supposed to be "
00538 "same)", reqId, lastId);
00539 return 1;
00540 }
00541 wpa_printf(MSG_DEBUG, "EAP: EAP-Success Id mismatch - reqId=%d "
00542 "lastId=%d", reqId, lastId);
00543 return 0;
00544 }
00545
00546
00547
00548
00549
00550
00551 static void eap_peer_sm_step_idle(struct eap_sm *sm)
00552 {
00553
00554
00555
00556
00557
00558 if (eapol_get_bool(sm, EAPOL_eapReq))
00559 SM_ENTER(EAP, RECEIVED);
00560 else if ((eapol_get_bool(sm, EAPOL_altAccept) &&
00561 sm->decision != DECISION_FAIL) ||
00562 (eapol_get_int(sm, EAPOL_idleWhile) == 0 &&
00563 sm->decision == DECISION_UNCOND_SUCC))
00564 SM_ENTER(EAP, SUCCESS);
00565 else if (eapol_get_bool(sm, EAPOL_altReject) ||
00566 (eapol_get_int(sm, EAPOL_idleWhile) == 0 &&
00567 sm->decision != DECISION_UNCOND_SUCC) ||
00568 (eapol_get_bool(sm, EAPOL_altAccept) &&
00569 sm->methodState != METHOD_CONT &&
00570 sm->decision == DECISION_FAIL))
00571 SM_ENTER(EAP, FAILURE);
00572 else if (sm->selectedMethod == EAP_TYPE_LEAP &&
00573 sm->leap_done && sm->decision != DECISION_FAIL &&
00574 sm->methodState == METHOD_DONE)
00575 SM_ENTER(EAP, SUCCESS);
00576 else if (sm->selectedMethod == EAP_TYPE_PEAP &&
00577 sm->peap_done && sm->decision != DECISION_FAIL &&
00578 sm->methodState == METHOD_DONE)
00579 SM_ENTER(EAP, SUCCESS);
00580 }
00581
00582
00583 static int eap_peer_req_is_duplicate(struct eap_sm *sm)
00584 {
00585 int duplicate;
00586
00587 duplicate = (sm->reqId == sm->lastId) && sm->rxReq;
00588 if (sm->workaround && duplicate &&
00589 os_memcmp(sm->req_md5, sm->last_md5, 16) != 0) {
00590
00591
00592
00593
00594
00595
00596
00597
00598 wpa_printf(MSG_DEBUG, "EAP: AS used the same Id again, but "
00599 "EAP packets were not identical");
00600 wpa_printf(MSG_DEBUG, "EAP: workaround - assume this is not a "
00601 "duplicate packet");
00602 duplicate = 0;
00603 }
00604
00605 return duplicate;
00606 }
00607
00608
00609 static void eap_peer_sm_step_received(struct eap_sm *sm)
00610 {
00611 int duplicate = eap_peer_req_is_duplicate(sm);
00612
00613
00614
00615
00616
00617
00618 if (sm->rxSuccess && sm->decision != DECISION_FAIL &&
00619 (sm->reqId == sm->lastId ||
00620 eap_success_workaround(sm, sm->reqId, sm->lastId)))
00621 SM_ENTER(EAP, SUCCESS);
00622 else if (sm->methodState != METHOD_CONT &&
00623 ((sm->rxFailure &&
00624 sm->decision != DECISION_UNCOND_SUCC) ||
00625 (sm->rxSuccess && sm->decision == DECISION_FAIL &&
00626 (sm->selectedMethod != EAP_TYPE_LEAP ||
00627 sm->methodState != METHOD_MAY_CONT))) &&
00628 (sm->reqId == sm->lastId ||
00629 eap_success_workaround(sm, sm->reqId, sm->lastId)))
00630 SM_ENTER(EAP, FAILURE);
00631 else if (sm->rxReq && duplicate)
00632 SM_ENTER(EAP, RETRANSMIT);
00633 else if (sm->rxReq && !duplicate &&
00634 sm->reqMethod == EAP_TYPE_NOTIFICATION &&
00635 sm->allowNotifications)
00636 SM_ENTER(EAP, NOTIFICATION);
00637 else if (sm->rxReq && !duplicate &&
00638 sm->selectedMethod == EAP_TYPE_NONE &&
00639 sm->reqMethod == EAP_TYPE_IDENTITY)
00640 SM_ENTER(EAP, IDENTITY);
00641 else if (sm->rxReq && !duplicate &&
00642 sm->selectedMethod == EAP_TYPE_NONE &&
00643 sm->reqMethod != EAP_TYPE_IDENTITY &&
00644 sm->reqMethod != EAP_TYPE_NOTIFICATION)
00645 SM_ENTER(EAP, GET_METHOD);
00646 else if (sm->rxReq && !duplicate &&
00647 sm->reqMethod == sm->selectedMethod &&
00648 sm->methodState != METHOD_DONE)
00649 SM_ENTER(EAP, METHOD);
00650 else if (sm->selectedMethod == EAP_TYPE_LEAP &&
00651 (sm->rxSuccess || sm->rxResp))
00652 SM_ENTER(EAP, METHOD);
00653 else
00654 SM_ENTER(EAP, DISCARD);
00655 }
00656
00657
00658 static void eap_peer_sm_step_local(struct eap_sm *sm)
00659 {
00660 switch (sm->EAP_state) {
00661 case EAP_INITIALIZE:
00662 SM_ENTER(EAP, IDLE);
00663 break;
00664 case EAP_DISABLED:
00665 if (eapol_get_bool(sm, EAPOL_portEnabled) &&
00666 !sm->force_disabled)
00667 SM_ENTER(EAP, INITIALIZE);
00668 break;
00669 case EAP_IDLE:
00670 eap_peer_sm_step_idle(sm);
00671 break;
00672 case EAP_RECEIVED:
00673 eap_peer_sm_step_received(sm);
00674 break;
00675 case EAP_GET_METHOD:
00676 if (sm->selectedMethod == sm->reqMethod)
00677 SM_ENTER(EAP, METHOD);
00678 else
00679 SM_ENTER(EAP, SEND_RESPONSE);
00680 break;
00681 case EAP_METHOD:
00682 if (sm->ignore)
00683 SM_ENTER(EAP, DISCARD);
00684 else
00685 SM_ENTER(EAP, SEND_RESPONSE);
00686 break;
00687 case EAP_SEND_RESPONSE:
00688 SM_ENTER(EAP, IDLE);
00689 break;
00690 case EAP_DISCARD:
00691 SM_ENTER(EAP, IDLE);
00692 break;
00693 case EAP_IDENTITY:
00694 SM_ENTER(EAP, SEND_RESPONSE);
00695 break;
00696 case EAP_NOTIFICATION:
00697 SM_ENTER(EAP, SEND_RESPONSE);
00698 break;
00699 case EAP_RETRANSMIT:
00700 SM_ENTER(EAP, SEND_RESPONSE);
00701 break;
00702 case EAP_SUCCESS:
00703 break;
00704 case EAP_FAILURE:
00705 break;
00706 }
00707 }
00708
00709
00710 SM_STEP(EAP)
00711 {
00712
00713 if (eapol_get_bool(sm, EAPOL_eapRestart) &&
00714 eapol_get_bool(sm, EAPOL_portEnabled))
00715 SM_ENTER_GLOBAL(EAP, INITIALIZE);
00716 else if (!eapol_get_bool(sm, EAPOL_portEnabled) || sm->force_disabled)
00717 SM_ENTER_GLOBAL(EAP, DISABLED);
00718 else if (sm->num_rounds > EAP_MAX_AUTH_ROUNDS) {
00719
00720
00721
00722
00723
00724
00725
00726
00727 if (sm->num_rounds == EAP_MAX_AUTH_ROUNDS + 1) {
00728 wpa_msg(sm->msg_ctx, MSG_INFO, "EAP: more than %d "
00729 "authentication rounds - abort",
00730 EAP_MAX_AUTH_ROUNDS);
00731 sm->num_rounds++;
00732 SM_ENTER_GLOBAL(EAP, FAILURE);
00733 }
00734 } else {
00735
00736 eap_peer_sm_step_local(sm);
00737 }
00738 }
00739
00740
00741 static Boolean eap_sm_allowMethod(struct eap_sm *sm, int vendor,
00742 EapType method)
00743 {
00744 if (!eap_allowed_method(sm, vendor, method)) {
00745 wpa_printf(MSG_DEBUG, "EAP: configuration does not allow: "
00746 "vendor %u method %u", vendor, method);
00747 return FALSE;
00748 }
00749 if (eap_peer_get_eap_method(vendor, method))
00750 return TRUE;
00751 wpa_printf(MSG_DEBUG, "EAP: not included in build: "
00752 "vendor %u method %u", vendor, method);
00753 return FALSE;
00754 }
00755
00756
00757 static struct wpabuf * eap_sm_build_expanded_nak(
00758 struct eap_sm *sm, int id, const struct eap_method *methods,
00759 size_t count)
00760 {
00761 struct wpabuf *resp;
00762 int found = 0;
00763 const struct eap_method *m;
00764
00765 wpa_printf(MSG_DEBUG, "EAP: Building expanded EAP-Nak");
00766
00767
00768 resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_EXPANDED,
00769 8 + 8 * (count + 1), EAP_CODE_RESPONSE, id);
00770 if (resp == NULL)
00771 return NULL;
00772
00773 wpabuf_put_be24(resp, EAP_VENDOR_IETF);
00774 wpabuf_put_be32(resp, EAP_TYPE_NAK);
00775
00776 for (m = methods; m; m = m->next) {
00777 if (sm->reqVendor == m->vendor &&
00778 sm->reqVendorMethod == m->method)
00779 continue;
00780 if (eap_allowed_method(sm, m->vendor, m->method)) {
00781 wpa_printf(MSG_DEBUG, "EAP: allowed type: "
00782 "vendor=%u method=%u",
00783 m->vendor, m->method);
00784 wpabuf_put_u8(resp, EAP_TYPE_EXPANDED);
00785 wpabuf_put_be24(resp, m->vendor);
00786 wpabuf_put_be32(resp, m->method);
00787
00788 found++;
00789 }
00790 }
00791 if (!found) {
00792 wpa_printf(MSG_DEBUG, "EAP: no more allowed methods");
00793 wpabuf_put_u8(resp, EAP_TYPE_EXPANDED);
00794 wpabuf_put_be24(resp, EAP_VENDOR_IETF);
00795 wpabuf_put_be32(resp, EAP_TYPE_NONE);
00796 }
00797
00798 eap_update_len(resp);
00799
00800 return resp;
00801 }
00802
00803
00804 static struct wpabuf * eap_sm_buildNak(struct eap_sm *sm, int id)
00805 {
00806 struct wpabuf *resp;
00807 u8 *start;
00808 int found = 0, expanded_found = 0;
00809 size_t count;
00810 const struct eap_method *methods, *m;
00811
00812 wpa_printf(MSG_DEBUG, "EAP: Building EAP-Nak (requested type %u "
00813 "vendor=%u method=%u not allowed)", sm->reqMethod,
00814 sm->reqVendor, sm->reqVendorMethod);
00815 methods = eap_peer_get_methods(&count);
00816 if (methods == NULL)
00817 return NULL;
00818 if (sm->reqMethod == EAP_TYPE_EXPANDED)
00819 return eap_sm_build_expanded_nak(sm, id, methods, count);
00820
00821
00822 resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_NAK,
00823 sizeof(struct eap_hdr) + 1 + count + 1,
00824 EAP_CODE_RESPONSE, id);
00825 if (resp == NULL)
00826 return NULL;
00827
00828 start = wpabuf_put(resp, 0);
00829 for (m = methods; m; m = m->next) {
00830 if (m->vendor == EAP_VENDOR_IETF && m->method == sm->reqMethod)
00831 continue;
00832 if (eap_allowed_method(sm, m->vendor, m->method)) {
00833 if (m->vendor != EAP_VENDOR_IETF) {
00834 if (expanded_found)
00835 continue;
00836 expanded_found = 1;
00837 wpabuf_put_u8(resp, EAP_TYPE_EXPANDED);
00838 } else
00839 wpabuf_put_u8(resp, m->method);
00840 found++;
00841 }
00842 }
00843 if (!found)
00844 wpabuf_put_u8(resp, EAP_TYPE_NONE);
00845 wpa_hexdump(MSG_DEBUG, "EAP: allowed methods", start, found);
00846
00847 eap_update_len(resp);
00848
00849 return resp;
00850 }
00851
00852
00853 static void eap_sm_processIdentity(struct eap_sm *sm, const struct wpabuf *req)
00854 {
00855 const struct eap_hdr *hdr = wpabuf_head(req);
00856 const u8 *pos = (const u8 *) (hdr + 1);
00857 pos++;
00858
00859 wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_STARTED
00860 "EAP authentication started");
00861
00862
00863
00864
00865
00866
00867
00868
00869
00870
00871 wpa_hexdump_ascii(MSG_DEBUG, "EAP: EAP-Request Identity data",
00872 pos, be_to_host16(hdr->length) - 5);
00873 }
00874
00875
00876 #ifdef PCSC_FUNCS
00877 static int eap_sm_imsi_identity(struct eap_sm *sm,
00878 struct eap_peer_config *conf)
00879 {
00880 int aka = 0;
00881 char imsi[100];
00882 size_t imsi_len;
00883 struct eap_method_type *m = conf->eap_methods;
00884 int i;
00885
00886 imsi_len = sizeof(imsi);
00887 if (scard_get_imsi(sm->scard_ctx, imsi, &imsi_len)) {
00888 wpa_printf(MSG_WARNING, "Failed to get IMSI from SIM");
00889 return -1;
00890 }
00891
00892 wpa_hexdump_ascii(MSG_DEBUG, "IMSI", (u8 *) imsi, imsi_len);
00893
00894 for (i = 0; m && (m[i].vendor != EAP_VENDOR_IETF ||
00895 m[i].method != EAP_TYPE_NONE); i++) {
00896 if (m[i].vendor == EAP_VENDOR_IETF &&
00897 m[i].method == EAP_TYPE_AKA) {
00898 aka = 1;
00899 break;
00900 }
00901 }
00902
00903 os_free(conf->identity);
00904 conf->identity = os_malloc(1 + imsi_len);
00905 if (conf->identity == NULL) {
00906 wpa_printf(MSG_WARNING, "Failed to allocate buffer for "
00907 "IMSI-based identity");
00908 return -1;
00909 }
00910
00911 conf->identity[0] = aka ? '0' : '1';
00912 os_memcpy(conf->identity + 1, imsi, imsi_len);
00913 conf->identity_len = 1 + imsi_len;
00914
00915 return 0;
00916 }
00917 #endif
00918
00919
00920 static int eap_sm_set_scard_pin(struct eap_sm *sm,
00921 struct eap_peer_config *conf)
00922 {
00923 #ifdef PCSC_FUNCS
00924 if (scard_set_pin(sm->scard_ctx, conf->pin)) {
00925
00926
00927
00928
00929 os_free(conf->pin);
00930 conf->pin = NULL;
00931
00932 wpa_printf(MSG_WARNING, "PIN validation failed");
00933 eap_sm_request_pin(sm);
00934 return -1;
00935 }
00936 return 0;
00937 #else
00938 return -1;
00939 #endif
00940 }
00941
00942 static int eap_sm_get_scard_identity(struct eap_sm *sm,
00943 struct eap_peer_config *conf)
00944 {
00945 #ifdef PCSC_FUNCS
00946 if (eap_sm_set_scard_pin(sm, conf))
00947 return -1;
00948
00949 return eap_sm_imsi_identity(sm, conf);
00950 #else
00951 return -1;
00952 #endif
00953 }
00954
00955
00967 struct wpabuf * eap_sm_buildIdentity(struct eap_sm *sm, int id, int encrypted)
00968 {
00969 struct eap_peer_config *config = eap_get_config(sm);
00970 struct wpabuf *resp;
00971 const u8 *identity;
00972 size_t identity_len;
00973
00974 if (config == NULL) {
00975 wpa_printf(MSG_WARNING, "EAP: buildIdentity: configuration "
00976 "was not available");
00977 return NULL;
00978 }
00979
00980 if (sm->m && sm->m->get_identity &&
00981 (identity = sm->m->get_identity(sm, sm->eap_method_priv,
00982 &identity_len)) != NULL) {
00983 wpa_hexdump_ascii(MSG_DEBUG, "EAP: using method re-auth "
00984 "identity", identity, identity_len);
00985 } else if (!encrypted && config->anonymous_identity) {
00986 identity = config->anonymous_identity;
00987 identity_len = config->anonymous_identity_len;
00988 wpa_hexdump_ascii(MSG_DEBUG, "EAP: using anonymous identity",
00989 identity, identity_len);
00990 } else {
00991 identity = config->identity;
00992 identity_len = config->identity_len;
00993 wpa_hexdump_ascii(MSG_DEBUG, "EAP: using real identity",
00994 identity, identity_len);
00995 }
00996
00997 if (identity == NULL) {
00998 wpa_printf(MSG_WARNING, "EAP: buildIdentity: identity "
00999 "configuration was not available");
01000 if (config->pcsc) {
01001 if (eap_sm_get_scard_identity(sm, config) < 0)
01002 return NULL;
01003 identity = config->identity;
01004 identity_len = config->identity_len;
01005 wpa_hexdump_ascii(MSG_DEBUG, "permanent identity from "
01006 "IMSI", identity, identity_len);
01007 } else {
01008 eap_sm_request_identity(sm);
01009 return NULL;
01010 }
01011 } else if (config->pcsc) {
01012 if (eap_sm_set_scard_pin(sm, config) < 0)
01013 return NULL;
01014 }
01015
01016 resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY, identity_len,
01017 EAP_CODE_RESPONSE, id);
01018 if (resp == NULL)
01019 return NULL;
01020
01021 wpabuf_put_data(resp, identity, identity_len);
01022
01023 return resp;
01024 }
01025
01026
01027 static void eap_sm_processNotify(struct eap_sm *sm, const struct wpabuf *req)
01028 {
01029 const u8 *pos;
01030 char *msg;
01031 size_t i, msg_len;
01032
01033 pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_NOTIFICATION, req,
01034 &msg_len);
01035 if (pos == NULL)
01036 return;
01037 wpa_hexdump_ascii(MSG_DEBUG, "EAP: EAP-Request Notification data",
01038 pos, msg_len);
01039
01040 msg = os_malloc(msg_len + 1);
01041 if (msg == NULL)
01042 return;
01043 for (i = 0; i < msg_len; i++)
01044 msg[i] = isprint(pos[i]) ? (char) pos[i] : '_';
01045 msg[msg_len] = '\0';
01046 wpa_msg(sm->msg_ctx, MSG_INFO, "%s%s",
01047 WPA_EVENT_EAP_NOTIFICATION, msg);
01048 os_free(msg);
01049 }
01050
01051
01052 static struct wpabuf * eap_sm_buildNotify(int id)
01053 {
01054 struct wpabuf *resp;
01055
01056 wpa_printf(MSG_DEBUG, "EAP: Generating EAP-Response Notification");
01057 resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_NOTIFICATION, 0,
01058 EAP_CODE_RESPONSE, id);
01059 if (resp == NULL)
01060 return NULL;
01061
01062 return resp;
01063 }
01064
01065
01066 static void eap_sm_parseEapReq(struct eap_sm *sm, const struct wpabuf *req)
01067 {
01068 const struct eap_hdr *hdr;
01069 size_t plen;
01070 const u8 *pos;
01071
01072 sm->rxReq = sm->rxResp = sm->rxSuccess = sm->rxFailure = FALSE;
01073 sm->reqId = 0;
01074 sm->reqMethod = EAP_TYPE_NONE;
01075 sm->reqVendor = EAP_VENDOR_IETF;
01076 sm->reqVendorMethod = EAP_TYPE_NONE;
01077
01078 if (req == NULL || wpabuf_len(req) < sizeof(*hdr))
01079 return;
01080
01081 hdr = wpabuf_head(req);
01082 plen = be_to_host16(hdr->length);
01083 if (plen > wpabuf_len(req)) {
01084 wpa_printf(MSG_DEBUG, "EAP: Ignored truncated EAP-Packet "
01085 "(len=%lu plen=%lu)",
01086 (unsigned long) wpabuf_len(req),
01087 (unsigned long) plen);
01088 return;
01089 }
01090
01091 sm->reqId = hdr->identifier;
01092
01093 if (sm->workaround) {
01094 const u8 *addr[1];
01095 addr[0] = wpabuf_head(req);
01096 md5_vector(1, addr, &plen, sm->req_md5);
01097 }
01098
01099 switch (hdr->code) {
01100 case EAP_CODE_REQUEST:
01101 if (plen < sizeof(*hdr) + 1) {
01102 wpa_printf(MSG_DEBUG, "EAP: Too short EAP-Request - "
01103 "no Type field");
01104 return;
01105 }
01106 sm->rxReq = TRUE;
01107 pos = (const u8 *) (hdr + 1);
01108 sm->reqMethod = *pos++;
01109 if (sm->reqMethod == EAP_TYPE_EXPANDED) {
01110 if (plen < sizeof(*hdr) + 8) {
01111 wpa_printf(MSG_DEBUG, "EAP: Ignored truncated "
01112 "expanded EAP-Packet (plen=%lu)",
01113 (unsigned long) plen);
01114 return;
01115 }
01116 sm->reqVendor = WPA_GET_BE24(pos);
01117 pos += 3;
01118 sm->reqVendorMethod = WPA_GET_BE32(pos);
01119 }
01120 wpa_printf(MSG_DEBUG, "EAP: Received EAP-Request id=%d "
01121 "method=%u vendor=%u vendorMethod=%u",
01122 sm->reqId, sm->reqMethod, sm->reqVendor,
01123 sm->reqVendorMethod);
01124 break;
01125 case EAP_CODE_RESPONSE:
01126 if (sm->selectedMethod == EAP_TYPE_LEAP) {
01127
01128
01129
01130
01131
01132 if (plen < sizeof(*hdr) + 1) {
01133 wpa_printf(MSG_DEBUG, "EAP: Too short "
01134 "EAP-Response - no Type field");
01135 return;
01136 }
01137 sm->rxResp = TRUE;
01138 pos = (const u8 *) (hdr + 1);
01139 sm->reqMethod = *pos;
01140 wpa_printf(MSG_DEBUG, "EAP: Received EAP-Response for "
01141 "LEAP method=%d id=%d",
01142 sm->reqMethod, sm->reqId);
01143 break;
01144 }
01145 wpa_printf(MSG_DEBUG, "EAP: Ignored EAP-Response");
01146 break;
01147 case EAP_CODE_SUCCESS:
01148 wpa_printf(MSG_DEBUG, "EAP: Received EAP-Success");
01149 sm->rxSuccess = TRUE;
01150 break;
01151 case EAP_CODE_FAILURE:
01152 wpa_printf(MSG_DEBUG, "EAP: Received EAP-Failure");
01153 sm->rxFailure = TRUE;
01154 break;
01155 default:
01156 wpa_printf(MSG_DEBUG, "EAP: Ignored EAP-Packet with unknown "
01157 "code %d", hdr->code);
01158 break;
01159 }
01160 }
01161
01162
01163 static void eap_peer_sm_tls_event(void *ctx, enum tls_event ev,
01164 union tls_event_data *data)
01165 {
01166 struct eap_sm *sm = ctx;
01167 char *hash_hex = NULL;
01168 char *cert_hex = NULL;
01169
01170 switch (ev) {
01171 case TLS_CERT_CHAIN_FAILURE:
01172 wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_TLS_CERT_ERROR
01173 "reason=%d depth=%d subject='%s' err='%s'",
01174 data->cert_fail.reason,
01175 data->cert_fail.depth,
01176 data->cert_fail.subject,
01177 data->cert_fail.reason_txt);
01178 break;
01179 case TLS_PEER_CERTIFICATE:
01180 if (data->peer_cert.hash) {
01181 size_t len = data->peer_cert.hash_len * 2 + 1;
01182 hash_hex = os_malloc(len);
01183 if (hash_hex) {
01184 wpa_snprintf_hex(hash_hex, len,
01185 data->peer_cert.hash,
01186 data->peer_cert.hash_len);
01187 }
01188 }
01189 wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PEER_CERT
01190 "depth=%d subject='%s'%s%s",
01191 data->peer_cert.depth, data->peer_cert.subject,
01192 hash_hex ? " hash=" : "", hash_hex ? hash_hex : "");
01193
01194 if (data->peer_cert.cert) {
01195 size_t len = wpabuf_len(data->peer_cert.cert) * 2 + 1;
01196 cert_hex = os_malloc(len);
01197 if (cert_hex == NULL)
01198 break;
01199 wpa_snprintf_hex(cert_hex, len,
01200 wpabuf_head(data->peer_cert.cert),
01201 wpabuf_len(data->peer_cert.cert));
01202 wpa_msg_ctrl(sm->msg_ctx, MSG_INFO,
01203 WPA_EVENT_EAP_PEER_CERT
01204 "depth=%d subject='%s' cert=%s",
01205 data->peer_cert.depth,
01206 data->peer_cert.subject,
01207 cert_hex);
01208 }
01209 break;
01210 }
01211
01212 os_free(hash_hex);
01213 os_free(cert_hex);
01214 }
01215
01216
01231 struct eap_sm * eap_peer_sm_init(void *eapol_ctx,
01232 struct eapol_callbacks *eapol_cb,
01233 void *msg_ctx, struct eap_config *conf)
01234 {
01235 struct eap_sm *sm;
01236 struct tls_config tlsconf;
01237
01238 sm = os_zalloc(sizeof(*sm));
01239 if (sm == NULL)
01240 return NULL;
01241 sm->eapol_ctx = eapol_ctx;
01242 sm->eapol_cb = eapol_cb;
01243 sm->msg_ctx = msg_ctx;
01244 sm->ClientTimeout = 60;
01245 sm->wps = conf->wps;
01246
01247 os_memset(&tlsconf, 0, sizeof(tlsconf));
01248 tlsconf.opensc_engine_path = conf->opensc_engine_path;
01249 tlsconf.pkcs11_engine_path = conf->pkcs11_engine_path;
01250 tlsconf.pkcs11_module_path = conf->pkcs11_module_path;
01251 #ifdef CONFIG_FIPS
01252 tlsconf.fips_mode = 1;
01253 #endif
01254 tlsconf.event_cb = eap_peer_sm_tls_event;
01255 tlsconf.cb_ctx = sm;
01256 sm->ssl_ctx = tls_init(&tlsconf);
01257 if (sm->ssl_ctx == NULL) {
01258 wpa_printf(MSG_WARNING, "SSL: Failed to initialize TLS "
01259 "context.");
01260 os_free(sm);
01261 return NULL;
01262 }
01263
01264 return sm;
01265 }
01266
01267
01275 void eap_peer_sm_deinit(struct eap_sm *sm)
01276 {
01277 if (sm == NULL)
01278 return;
01279 eap_deinit_prev_method(sm, "EAP deinit");
01280 eap_sm_abort(sm);
01281 tls_deinit(sm->ssl_ctx);
01282 os_free(sm);
01283 }
01284
01285
01295 int eap_peer_sm_step(struct eap_sm *sm)
01296 {
01297 int res = 0;
01298 do {
01299 sm->changed = FALSE;
01300 SM_STEP_RUN(EAP);
01301 if (sm->changed)
01302 res = 1;
01303 } while (sm->changed);
01304 return res;
01305 }
01306
01307
01315 void eap_sm_abort(struct eap_sm *sm)
01316 {
01317 wpabuf_free(sm->lastRespData);
01318 sm->lastRespData = NULL;
01319 wpabuf_free(sm->eapRespData);
01320 sm->eapRespData = NULL;
01321 os_free(sm->eapKeyData);
01322 sm->eapKeyData = NULL;
01323
01324
01325
01326
01327 eapol_set_bool(sm, EAPOL_eapSuccess, FALSE);
01328 }
01329
01330
01331 #ifdef CONFIG_CTRL_IFACE
01332 static const char * eap_sm_state_txt(int state)
01333 {
01334 switch (state) {
01335 case EAP_INITIALIZE:
01336 return "INITIALIZE";
01337 case EAP_DISABLED:
01338 return "DISABLED";
01339 case EAP_IDLE:
01340 return "IDLE";
01341 case EAP_RECEIVED:
01342 return "RECEIVED";
01343 case EAP_GET_METHOD:
01344 return "GET_METHOD";
01345 case EAP_METHOD:
01346 return "METHOD";
01347 case EAP_SEND_RESPONSE:
01348 return "SEND_RESPONSE";
01349 case EAP_DISCARD:
01350 return "DISCARD";
01351 case EAP_IDENTITY:
01352 return "IDENTITY";
01353 case EAP_NOTIFICATION:
01354 return "NOTIFICATION";
01355 case EAP_RETRANSMIT:
01356 return "RETRANSMIT";
01357 case EAP_SUCCESS:
01358 return "SUCCESS";
01359 case EAP_FAILURE:
01360 return "FAILURE";
01361 default:
01362 return "UNKNOWN";
01363 }
01364 }
01365 #endif
01366
01367
01368 #if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
01369 static const char * eap_sm_method_state_txt(EapMethodState state)
01370 {
01371 switch (state) {
01372 case METHOD_NONE:
01373 return "NONE";
01374 case METHOD_INIT:
01375 return "INIT";
01376 case METHOD_CONT:
01377 return "CONT";
01378 case METHOD_MAY_CONT:
01379 return "MAY_CONT";
01380 case METHOD_DONE:
01381 return "DONE";
01382 default:
01383 return "UNKNOWN";
01384 }
01385 }
01386
01387
01388 static const char * eap_sm_decision_txt(EapDecision decision)
01389 {
01390 switch (decision) {
01391 case DECISION_FAIL:
01392 return "FAIL";
01393 case DECISION_COND_SUCC:
01394 return "COND_SUCC";
01395 case DECISION_UNCOND_SUCC:
01396 return "UNCOND_SUCC";
01397 default:
01398 return "UNKNOWN";
01399 }
01400 }
01401 #endif
01402
01403
01404 #ifdef CONFIG_CTRL_IFACE
01405
01419 int eap_sm_get_status(struct eap_sm *sm, char *buf, size_t buflen, int verbose)
01420 {
01421 int len, ret;
01422
01423 if (sm == NULL)
01424 return 0;
01425
01426 len = os_snprintf(buf, buflen,
01427 "EAP state=%s\n",
01428 eap_sm_state_txt(sm->EAP_state));
01429 if (len < 0 || (size_t) len >= buflen)
01430 return 0;
01431
01432 if (sm->selectedMethod != EAP_TYPE_NONE) {
01433 const char *name;
01434 if (sm->m) {
01435 name = sm->m->name;
01436 } else {
01437 const struct eap_method *m =
01438 eap_peer_get_eap_method(EAP_VENDOR_IETF,
01439 sm->selectedMethod);
01440 if (m)
01441 name = m->name;
01442 else
01443 name = "?";
01444 }
01445 ret = os_snprintf(buf + len, buflen - len,
01446 "selectedMethod=%d (EAP-%s)\n",
01447 sm->selectedMethod, name);
01448 if (ret < 0 || (size_t) ret >= buflen - len)
01449 return len;
01450 len += ret;
01451
01452 if (sm->m && sm->m->get_status) {
01453 len += sm->m->get_status(sm, sm->eap_method_priv,
01454 buf + len, buflen - len,
01455 verbose);
01456 }
01457 }
01458
01459 if (verbose) {
01460 ret = os_snprintf(buf + len, buflen - len,
01461 "reqMethod=%d\n"
01462 "methodState=%s\n"
01463 "decision=%s\n"
01464 "ClientTimeout=%d\n",
01465 sm->reqMethod,
01466 eap_sm_method_state_txt(sm->methodState),
01467 eap_sm_decision_txt(sm->decision),
01468 sm->ClientTimeout);
01469 if (ret < 0 || (size_t) ret >= buflen - len)
01470 return len;
01471 len += ret;
01472 }
01473
01474 return len;
01475 }
01476 #endif
01477
01478
01479 #if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
01480 typedef enum {
01481 TYPE_IDENTITY, TYPE_PASSWORD, TYPE_OTP, TYPE_PIN, TYPE_NEW_PASSWORD,
01482 TYPE_PASSPHRASE
01483 } eap_ctrl_req_type;
01484
01485 static void eap_sm_request(struct eap_sm *sm, eap_ctrl_req_type type,
01486 const char *msg, size_t msglen)
01487 {
01488 struct eap_peer_config *config;
01489 char *field, *txt, *tmp;
01490
01491 if (sm == NULL)
01492 return;
01493 config = eap_get_config(sm);
01494 if (config == NULL)
01495 return;
01496
01497 switch (type) {
01498 case TYPE_IDENTITY:
01499 field = "IDENTITY";
01500 txt = "Identity";
01501 config->pending_req_identity++;
01502 break;
01503 case TYPE_PASSWORD:
01504 field = "PASSWORD";
01505 txt = "Password";
01506 config->pending_req_password++;
01507 break;
01508 case TYPE_NEW_PASSWORD:
01509 field = "NEW_PASSWORD";
01510 txt = "New Password";
01511 config->pending_req_new_password++;
01512 break;
01513 case TYPE_PIN:
01514 field = "PIN";
01515 txt = "PIN";
01516 config->pending_req_pin++;
01517 break;
01518 case TYPE_OTP:
01519 field = "OTP";
01520 if (msg) {
01521 tmp = os_malloc(msglen + 3);
01522 if (tmp == NULL)
01523 return;
01524 tmp[0] = '[';
01525 os_memcpy(tmp + 1, msg, msglen);
01526 tmp[msglen + 1] = ']';
01527 tmp[msglen + 2] = '\0';
01528 txt = tmp;
01529 os_free(config->pending_req_otp);
01530 config->pending_req_otp = tmp;
01531 config->pending_req_otp_len = msglen + 3;
01532 } else {
01533 if (config->pending_req_otp == NULL)
01534 return;
01535 txt = config->pending_req_otp;
01536 }
01537 break;
01538 case TYPE_PASSPHRASE:
01539 field = "PASSPHRASE";
01540 txt = "Private key passphrase";
01541 config->pending_req_passphrase++;
01542 break;
01543 default:
01544 return;
01545 }
01546
01547 if (sm->eapol_cb->eap_param_needed)
01548 sm->eapol_cb->eap_param_needed(sm->eapol_ctx, field, txt);
01549 }
01550 #else
01551 #define eap_sm_request(sm, type, msg, msglen) do { } while (0)
01552 #endif
01553
01554
01564 void eap_sm_request_identity(struct eap_sm *sm)
01565 {
01566 eap_sm_request(sm, TYPE_IDENTITY, NULL, 0);
01567 }
01568
01569
01579 void eap_sm_request_password(struct eap_sm *sm)
01580 {
01581 eap_sm_request(sm, TYPE_PASSWORD, NULL, 0);
01582 }
01583
01584
01594 void eap_sm_request_new_password(struct eap_sm *sm)
01595 {
01596 eap_sm_request(sm, TYPE_NEW_PASSWORD, NULL, 0);
01597 }
01598
01599
01609 void eap_sm_request_pin(struct eap_sm *sm)
01610 {
01611 eap_sm_request(sm, TYPE_PIN, NULL, 0);
01612 }
01613
01614
01625 void eap_sm_request_otp(struct eap_sm *sm, const char *msg, size_t msg_len)
01626 {
01627 eap_sm_request(sm, TYPE_OTP, msg, msg_len);
01628 }
01629
01630
01640 void eap_sm_request_passphrase(struct eap_sm *sm)
01641 {
01642 eap_sm_request(sm, TYPE_PASSPHRASE, NULL, 0);
01643 }
01644
01645
01653 void eap_sm_notify_ctrl_attached(struct eap_sm *sm)
01654 {
01655 struct eap_peer_config *config = eap_get_config(sm);
01656
01657 if (config == NULL)
01658 return;
01659
01660
01661
01662
01663
01664 if (config->pending_req_identity)
01665 eap_sm_request_identity(sm);
01666 if (config->pending_req_password)
01667 eap_sm_request_password(sm);
01668 if (config->pending_req_new_password)
01669 eap_sm_request_new_password(sm);
01670 if (config->pending_req_otp)
01671 eap_sm_request_otp(sm, NULL, 0);
01672 if (config->pending_req_pin)
01673 eap_sm_request_pin(sm);
01674 if (config->pending_req_passphrase)
01675 eap_sm_request_passphrase(sm);
01676 }
01677
01678
01679 static int eap_allowed_phase2_type(int vendor, int type)
01680 {
01681 if (vendor != EAP_VENDOR_IETF)
01682 return 0;
01683 return type != EAP_TYPE_PEAP && type != EAP_TYPE_TTLS &&
01684 type != EAP_TYPE_FAST;
01685 }
01686
01687
01698 u32 eap_get_phase2_type(const char *name, int *vendor)
01699 {
01700 int v;
01701 u8 type = eap_peer_get_type(name, &v);
01702 if (eap_allowed_phase2_type(v, type)) {
01703 *vendor = v;
01704 return type;
01705 }
01706 *vendor = EAP_VENDOR_IETF;
01707 return EAP_TYPE_NONE;
01708 }
01709
01710
01720 struct eap_method_type * eap_get_phase2_types(struct eap_peer_config *config,
01721 size_t *count)
01722 {
01723 struct eap_method_type *buf;
01724 u32 method;
01725 int vendor;
01726 size_t mcount;
01727 const struct eap_method *methods, *m;
01728
01729 methods = eap_peer_get_methods(&mcount);
01730 if (methods == NULL)
01731 return NULL;
01732 *count = 0;
01733 buf = os_malloc(mcount * sizeof(struct eap_method_type));
01734 if (buf == NULL)
01735 return NULL;
01736
01737 for (m = methods; m; m = m->next) {
01738 vendor = m->vendor;
01739 method = m->method;
01740 if (eap_allowed_phase2_type(vendor, method)) {
01741 if (vendor == EAP_VENDOR_IETF &&
01742 method == EAP_TYPE_TLS && config &&
01743 config->private_key2 == NULL)
01744 continue;
01745 buf[*count].vendor = vendor;
01746 buf[*count].method = method;
01747 (*count)++;
01748 }
01749 }
01750
01751 return buf;
01752 }
01753
01754
01760 void eap_set_fast_reauth(struct eap_sm *sm, int enabled)
01761 {
01762 sm->fast_reauth = enabled;
01763 }
01764
01765
01771 void eap_set_workaround(struct eap_sm *sm, unsigned int workaround)
01772 {
01773 sm->workaround = workaround;
01774 }
01775
01776
01787 struct eap_peer_config * eap_get_config(struct eap_sm *sm)
01788 {
01789 return sm->eapol_cb->get_config(sm->eapol_ctx);
01790 }
01791
01792
01799 const u8 * eap_get_config_identity(struct eap_sm *sm, size_t *len)
01800 {
01801 struct eap_peer_config *config = eap_get_config(sm);
01802 if (config == NULL)
01803 return NULL;
01804 *len = config->identity_len;
01805 return config->identity;
01806 }
01807
01808
01815 const u8 * eap_get_config_password(struct eap_sm *sm, size_t *len)
01816 {
01817 struct eap_peer_config *config = eap_get_config(sm);
01818 if (config == NULL)
01819 return NULL;
01820 *len = config->password_len;
01821 return config->password;
01822 }
01823
01824
01834 const u8 * eap_get_config_password2(struct eap_sm *sm, size_t *len, int *hash)
01835 {
01836 struct eap_peer_config *config = eap_get_config(sm);
01837 if (config == NULL)
01838 return NULL;
01839 *len = config->password_len;
01840 if (hash)
01841 *hash = !!(config->flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH);
01842 return config->password;
01843 }
01844
01845
01852 const u8 * eap_get_config_new_password(struct eap_sm *sm, size_t *len)
01853 {
01854 struct eap_peer_config *config = eap_get_config(sm);
01855 if (config == NULL)
01856 return NULL;
01857 *len = config->new_password_len;
01858 return config->new_password;
01859 }
01860
01861
01868 const u8 * eap_get_config_otp(struct eap_sm *sm, size_t *len)
01869 {
01870 struct eap_peer_config *config = eap_get_config(sm);
01871 if (config == NULL)
01872 return NULL;
01873 *len = config->otp_len;
01874 return config->otp;
01875 }
01876
01877
01886 void eap_clear_config_otp(struct eap_sm *sm)
01887 {
01888 struct eap_peer_config *config = eap_get_config(sm);
01889 if (config == NULL)
01890 return;
01891 os_memset(config->otp, 0, config->otp_len);
01892 os_free(config->otp);
01893 config->otp = NULL;
01894 config->otp_len = 0;
01895 }
01896
01897
01903 const char * eap_get_config_phase1(struct eap_sm *sm)
01904 {
01905 struct eap_peer_config *config = eap_get_config(sm);
01906 if (config == NULL)
01907 return NULL;
01908 return config->phase1;
01909 }
01910
01911
01917 const char * eap_get_config_phase2(struct eap_sm *sm)
01918 {
01919 struct eap_peer_config *config = eap_get_config(sm);
01920 if (config == NULL)
01921 return NULL;
01922 return config->phase2;
01923 }
01924
01925
01931 int eap_key_available(struct eap_sm *sm)
01932 {
01933 return sm ? sm->eapKeyAvailable : 0;
01934 }
01935
01936
01946 void eap_notify_success(struct eap_sm *sm)
01947 {
01948 if (sm) {
01949 sm->decision = DECISION_COND_SUCC;
01950 sm->EAP_state = EAP_SUCCESS;
01951 }
01952 }
01953
01954
01962 void eap_notify_lower_layer_success(struct eap_sm *sm)
01963 {
01964 if (sm == NULL)
01965 return;
01966
01967 if (eapol_get_bool(sm, EAPOL_eapSuccess) ||
01968 sm->decision == DECISION_FAIL ||
01969 (sm->methodState != METHOD_MAY_CONT &&
01970 sm->methodState != METHOD_DONE))
01971 return;
01972
01973 if (sm->eapKeyData != NULL)
01974 sm->eapKeyAvailable = TRUE;
01975 eapol_set_bool(sm, EAPOL_eapSuccess, TRUE);
01976 wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS
01977 "EAP authentication completed successfully (based on lower "
01978 "layer success)");
01979 }
01980
01981
01993 const u8 * eap_get_eapKeyData(struct eap_sm *sm, size_t *len)
01994 {
01995 if (sm == NULL || sm->eapKeyData == NULL) {
01996 *len = 0;
01997 return NULL;
01998 }
01999
02000 *len = sm->eapKeyDataLen;
02001 return sm->eapKeyData;
02002 }
02003
02004
02015 struct wpabuf * eap_get_eapRespData(struct eap_sm *sm)
02016 {
02017 struct wpabuf *resp;
02018
02019 if (sm == NULL || sm->eapRespData == NULL)
02020 return NULL;
02021
02022 resp = sm->eapRespData;
02023 sm->eapRespData = NULL;
02024
02025 return resp;
02026 }
02027
02028
02037 void eap_register_scard_ctx(struct eap_sm *sm, void *ctx)
02038 {
02039 if (sm)
02040 sm->scard_ctx = ctx;
02041 }
02042
02043
02052 void eap_set_config_blob(struct eap_sm *sm, struct wpa_config_blob *blob)
02053 {
02054 #ifndef CONFIG_NO_CONFIG_BLOBS
02055 sm->eapol_cb->set_config_blob(sm->eapol_ctx, blob);
02056 #endif
02057 }
02058
02059
02066 const struct wpa_config_blob * eap_get_config_blob(struct eap_sm *sm,
02067 const char *name)
02068 {
02069 #ifndef CONFIG_NO_CONFIG_BLOBS
02070 return sm->eapol_cb->get_config_blob(sm->eapol_ctx, name);
02071 #else
02072 return NULL;
02073 #endif
02074 }
02075
02076
02085 void eap_set_force_disabled(struct eap_sm *sm, int disabled)
02086 {
02087 sm->force_disabled = disabled;
02088 }
02089
02090
02100 void eap_notify_pending(struct eap_sm *sm)
02101 {
02102 sm->eapol_cb->notify_pending(sm->eapol_ctx);
02103 }
02104
02105
02110 void eap_invalidate_cached_session(struct eap_sm *sm)
02111 {
02112 if (sm)
02113 eap_deinit_prev_method(sm, "invalidate");
02114 }
02115
02116
02117 int eap_is_wps_pbc_enrollee(struct eap_peer_config *conf)
02118 {
02119 if (conf->identity_len != WSC_ID_ENROLLEE_LEN ||
02120 os_memcmp(conf->identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN))
02121 return 0;
02122
02123 if (conf->phase1 == NULL || os_strstr(conf->phase1, "pbc=1") == NULL)
02124 return 0;
02125
02126 return 1;
02127 }
02128
02129
02130 int eap_is_wps_pin_enrollee(struct eap_peer_config *conf)
02131 {
02132 if (conf->identity_len != WSC_ID_ENROLLEE_LEN ||
02133 os_memcmp(conf->identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN))
02134 return 0;
02135
02136 if (conf->phase1 == NULL || os_strstr(conf->phase1, "pin=") == NULL)
02137 return 0;
02138
02139 return 1;
02140 }