/** * wpa_supplicant_scard_init - Initialize SIM/USIM access with PC/SC * @wpa_s: pointer to wpa_supplicant data * @ssid: Configuration data for the network * Returns: 0 on success, -1 on failure * * This function is called when starting authentication with a network that is * configured to use PC/SC for SIM/USIM access (EAP-SIM or EAP-AKA). */ int wpa_supplicant_scard_init(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) { #ifdef IEEE8021X_EAPOL int aka = 0, sim = 0, type; if (ssid->pcsc == NULL || wpa_s->scard != NULL) return 0; if (ssid->eap_methods == NULL) { sim = 1; aka = 1; } else { struct eap_method_type *eap = ssid->eap_methods; while (eap->vendor != EAP_VENDOR_IETF || eap->method != EAP_TYPE_NONE) { if (eap->vendor == EAP_VENDOR_IETF) { if (eap->method == EAP_TYPE_SIM) sim = 1; else if (eap->method == EAP_TYPE_AKA) aka = 1; } eap++; } } if (eap_sm_get_eap_methods(EAP_VENDOR_IETF, EAP_TYPE_SIM) == NULL) sim = 0; if (eap_sm_get_eap_methods(EAP_VENDOR_IETF, EAP_TYPE_AKA) == NULL) aka = 0; if (!sim && !aka) { wpa_printf(MSG_DEBUG, "Selected network is configured to use " "SIM, but neither EAP-SIM nor EAP-AKA are enabled"); return 0; } wpa_printf(MSG_DEBUG, "Selected network is configured to use SIM " "(sim=%d aka=%d) - initialize PCSC", sim, aka); if (sim && aka) type = SCARD_TRY_BOTH; else if (aka) type = SCARD_USIM_ONLY; else type = SCARD_GSM_SIM_ONLY; wpa_s->scard = scard_init(type); if (wpa_s->scard == NULL) { wpa_printf(MSG_WARNING, "Failed to initialize SIM " "(pcsc-lite)"); return -1; } wpa_sm_set_scard_ctx(wpa_s->wpa, wpa_s->scard); eapol_sm_register_scard_ctx(wpa_s->eapol, wpa_s->scard); #endif /* IEEE8021X_EAPOL */ return 0; }
SM_STATE(EAP, PROPOSE_METHOD) { SM_ENTRY(EAP, PROPOSE_METHOD); sm->currentMethod = eap_sm_Policy_getNextMethod(sm); if (sm->m && sm->eap_method_priv) { sm->m->reset(sm, sm->eap_method_priv); sm->eap_method_priv = NULL; } sm->m = eap_sm_get_eap_methods(sm->currentMethod); if (sm->m) { sm->eap_method_priv = sm->m->init(sm); if (sm->eap_method_priv == NULL) { wpa_printf(MSG_DEBUG, "EAP: Failed to initialize EAP " "method %d", sm->currentMethod); sm->m = NULL; sm->currentMethod = EAP_TYPE_NONE; } } if (sm->currentMethod == EAP_TYPE_IDENTITY || sm->currentMethod == EAP_TYPE_NOTIFICATION) sm->methodState = METHOD_CONTINUE; else sm->methodState = METHOD_PROPOSED; }
SM_STATE(EAP, PICK_UP_METHOD) { SM_ENTRY(EAP, PICK_UP_METHOD); if (eap_sm_Policy_doPickUp(sm, sm->respMethod)) { sm->currentMethod = sm->respMethod; if (sm->m && sm->eap_method_priv) { sm->m->reset(sm, sm->eap_method_priv); sm->eap_method_priv = NULL; } sm->m = eap_sm_get_eap_methods(sm->currentMethod); if (sm->m && sm->m->initPickUp) { sm->eap_method_priv = sm->m->initPickUp(sm); if (sm->eap_method_priv == NULL) { wpa_printf(MSG_DEBUG, "EAP: Failed to " "initialize EAP method %d", sm->currentMethod); sm->m = NULL; sm->currentMethod = EAP_TYPE_NONE; } } else { sm->m = NULL; sm->currentMethod = EAP_TYPE_NONE; } } }
SM_STATE(EAP, PROPOSE_METHOD) { int vendor; EapType type; SM_ENTRY(EAP, PROPOSE_METHOD); type = eap_sm_Policy_getNextMethod(sm, &vendor); if (vendor == EAP_VENDOR_IETF) sm->currentMethod = type; else sm->currentMethod = EAP_TYPE_EXPANDED; if (sm->m && sm->eap_method_priv) { sm->m->reset(sm, sm->eap_method_priv); sm->eap_method_priv = NULL; } sm->m = eap_sm_get_eap_methods(vendor, type); if (sm->m) { sm->eap_method_priv = sm->m->init(sm); if (sm->eap_method_priv == NULL) { wpa_printf(MSG_DEBUG, "EAP: Failed to initialize EAP " "method %d", sm->currentMethod); sm->m = NULL; sm->currentMethod = EAP_TYPE_NONE; } } if (sm->currentMethod == EAP_TYPE_IDENTITY || sm->currentMethod == EAP_TYPE_NOTIFICATION) sm->methodState = METHOD_CONTINUE; else sm->methodState = METHOD_PROPOSED; }
SM_STATE(EAP, GET_METHOD) { SM_ENTRY(EAP, GET_METHOD); if (eap_sm_allowMethod(sm, sm->reqMethod)) { int reinit = 0; if (sm->fast_reauth && sm->m && sm->m->method == sm->reqMethod && sm->m->has_reauth_data && sm->m->has_reauth_data(sm, sm->eap_method_priv)) { wpa_printf(MSG_DEBUG, "EAP: using previous method data" " for fast re-authentication"); reinit = 1; } else eap_deinit_prev_method(sm, "GET_METHOD"); sm->selectedMethod = sm->reqMethod; if (sm->m == NULL) sm->m = eap_sm_get_eap_methods(sm->selectedMethod); if (sm->m) { wpa_printf(MSG_DEBUG, "EAP: initialize selected EAP " "method (%d, %s)", sm->selectedMethod, sm->m->name); if (reinit) sm->eap_method_priv = sm->m->init_for_reauth( sm, sm->eap_method_priv); else sm->eap_method_priv = sm->m->init(sm); if (sm->eap_method_priv == NULL) { struct wpa_ssid *config = eap_get_config(sm); wpa_printf(MSG_DEBUG, "EAP: Failed to " "initialize EAP method %d", sm->selectedMethod); sm->m = NULL; sm->methodState = METHOD_NONE; sm->selectedMethod = EAP_TYPE_NONE; if (sm->reqMethod == EAP_TYPE_TLS && config && config->pending_req_pin) { /* * Return without generating Nak in * order to allow entering of PIN code * to retry the current EAP packet. */ wpa_printf(MSG_DEBUG, "EAP: Pending " "PIN request - skip Nak"); return; } } else { sm->methodState = METHOD_INIT; return; } } } free(sm->eapRespData); sm->eapRespData = eap_sm_buildNak(sm, sm->reqId, &sm->eapRespDataLen); }
int eap_sm_get_status(struct eap_sm *sm, char *buf, size_t buflen, int verbose) { int len; if (sm == NULL) return 0; len = snprintf(buf, buflen, "EAP state=%s\n", eap_sm_state_txt(sm->EAP_state)); if (sm->selectedMethod != EAP_TYPE_NONE) { const char *name; if (sm->m) { name = sm->m->name; } else { const struct eap_method *m = eap_sm_get_eap_methods(sm->selectedMethod); if (m) name = m->name; else name = "?"; } len += snprintf(buf + len, buflen - len, "selectedMethod=%d (EAP-%s)\n", sm->selectedMethod, name); if (sm->m && sm->m->get_status) { len += sm->m->get_status(sm, sm->eap_method_priv, buf + len, buflen - len, verbose); } } if (verbose) { len += snprintf(buf + len, buflen - len, "reqMethod=%d\n" "methodState=%s\n" "decision=%s\n" "ClientTimeout=%d\n", sm->reqMethod, eap_sm_method_state_txt(sm->methodState), eap_sm_decision_txt(sm->decision), sm->ClientTimeout); } return len; }
static int eap_peap_phase2_init(struct eap_sm *sm, struct eap_peap_data *data, u8 eap_type) { if (data->phase2_priv && data->phase2_method) { data->phase2_method->reset(sm, data->phase2_priv); data->phase2_method = NULL; data->phase2_priv = NULL; } data->phase2_method = eap_sm_get_eap_methods(eap_type); if (!data->phase2_method) return -1; sm->init_phase2 = 1; data->phase2_priv = data->phase2_method->init(sm); sm->init_phase2 = 0; return 0; }
static int eap_ttls_phase2_request_eap(struct eap_sm *sm, struct eap_ttls_data *data, struct eap_method_ret *ret, struct eap_hdr *hdr, u8 **resp, size_t *resp_len) { size_t len = be_to_host16(hdr->length); u8 *pos; struct eap_method_ret iret; struct wpa_ssid *config = eap_get_config(sm); if (len <= sizeof(struct eap_hdr)) { wpa_printf(MSG_INFO, "EAP-TTLS: too short " "Phase 2 request (len=%lu)", (unsigned long) len); return -1; } pos = (u8 *) (hdr + 1); wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 EAP Request: type=%d", *pos); switch (*pos) { case EAP_TYPE_IDENTITY: *resp = eap_sm_buildIdentity(sm, hdr->identifier, resp_len, 1); break; default: if (data->phase2_eap_type.vendor == EAP_VENDOR_IETF && data->phase2_eap_type.method == EAP_TYPE_NONE) { size_t i; for (i = 0; i < data->num_phase2_eap_types; i++) { if (data->phase2_eap_types[i].vendor != EAP_VENDOR_IETF || data->phase2_eap_types[i].method != *pos) continue; data->phase2_eap_type.vendor = data->phase2_eap_types[i].vendor; data->phase2_eap_type.method = data->phase2_eap_types[i].method; wpa_printf(MSG_DEBUG, "EAP-TTLS: Selected " "Phase 2 EAP vendor %d method %d", data->phase2_eap_type.vendor, data->phase2_eap_type.method); break; } } if (*pos != data->phase2_eap_type.method || *pos == EAP_TYPE_NONE) { if (eap_ttls_phase2_nak(data, hdr, resp, resp_len)) return -1; break; } if (data->phase2_priv == NULL) { data->phase2_method = eap_sm_get_eap_methods( EAP_VENDOR_IETF, *pos); if (data->phase2_method) { sm->init_phase2 = 1; sm->mschapv2_full_key = 1; data->phase2_priv = data->phase2_method->init(sm); sm->init_phase2 = 0; sm->mschapv2_full_key = 0; } } if (data->phase2_priv == NULL || data->phase2_method == NULL) { wpa_printf(MSG_INFO, "EAP-TTLS: failed to initialize " "Phase 2 EAP method %d", *pos); return -1; } os_memset(&iret, 0, sizeof(iret)); *resp = data->phase2_method->process(sm, data->phase2_priv, &iret, (u8 *) hdr, len, resp_len); if ((iret.methodState == METHOD_DONE || iret.methodState == METHOD_MAY_CONT) && (iret.decision == DECISION_UNCOND_SUCC || iret.decision == DECISION_COND_SUCC || iret.decision == DECISION_FAIL)) { ret->methodState = iret.methodState; ret->decision = iret.decision; } if (data->ttls_version > 0) { const struct eap_method *m = data->phase2_method; void *priv = data->phase2_priv; /* TTLSv1 requires TLS/IA FinalPhaseFinished */ if (ret->decision == DECISION_UNCOND_SUCC) ret->decision = DECISION_COND_SUCC; ret->methodState = METHOD_CONT; if (ret->decision == DECISION_COND_SUCC && m->isKeyAvailable && m->getKey && m->isKeyAvailable(sm, priv)) { u8 *key; size_t key_len; key = m->getKey(sm, priv, &key_len); if (key) { eap_ttls_ia_permute_inner_secret( sm, data, key, key_len); os_free(key); } } } break; } if (*resp == NULL && (config->pending_req_identity || config->pending_req_password || config->pending_req_otp)) { return 0; } if (*resp == NULL) return -1; wpa_hexdump(MSG_DEBUG, "EAP-TTLS: AVP encapsulate EAP Response", *resp, *resp_len); return eap_ttls_avp_encapsulate(resp, resp_len, RADIUS_ATTR_EAP_MESSAGE, 1); }