📄 eap.c
字号:
if (eapol_get_bool(sm, EAPOL_eapRestart) && eapol_get_bool(sm, EAPOL_portEnabled)) SM_ENTER_GLOBAL(EAP, INITIALIZE); else if (!eapol_get_bool(sm, EAPOL_portEnabled) || sm->force_disabled) SM_ENTER_GLOBAL(EAP, DISABLED); else if (sm->num_rounds > EAP_MAX_AUTH_ROUNDS) { /* RFC 4137 does not place any limit on number of EAP messages * in an authentication session. However, some error cases have * ended up in a state were EAP messages were sent between the * peer and server in a loop (e.g., TLS ACK frame in both * direction). Since this is quite undesired outcome, limit the * total number of EAP round-trips and abort authentication if * this limit is exceeded. */ if (sm->num_rounds == EAP_MAX_AUTH_ROUNDS + 1) { wpa_msg(sm->msg_ctx, MSG_INFO, "EAP: more than %d " "authentication rounds - abort", EAP_MAX_AUTH_ROUNDS); sm->num_rounds++; SM_ENTER_GLOBAL(EAP, FAILURE); } } else switch (sm->EAP_state) { case EAP_INITIALIZE: SM_ENTER(EAP, IDLE); break; case EAP_DISABLED: if (eapol_get_bool(sm, EAPOL_portEnabled) && !sm->force_disabled) SM_ENTER(EAP, INITIALIZE); break; case EAP_IDLE: /* * The first three transitions are from RFC 4137. The last two * are local additions to handle special cases with LEAP and * PEAP server not sending EAP-Success in some cases. */ if (eapol_get_bool(sm, EAPOL_eapReq)) SM_ENTER(EAP, RECEIVED); else if ((eapol_get_bool(sm, EAPOL_altAccept) && sm->decision != DECISION_FAIL) || (eapol_get_int(sm, EAPOL_idleWhile) == 0 && sm->decision == DECISION_UNCOND_SUCC)) SM_ENTER(EAP, SUCCESS); else if (eapol_get_bool(sm, EAPOL_altReject) || (eapol_get_int(sm, EAPOL_idleWhile) == 0 && sm->decision != DECISION_UNCOND_SUCC) || (eapol_get_bool(sm, EAPOL_altAccept) && sm->methodState != METHOD_CONT && sm->decision == DECISION_FAIL)) SM_ENTER(EAP, FAILURE); else if (sm->selectedMethod == EAP_TYPE_LEAP && sm->leap_done && sm->decision != DECISION_FAIL && sm->methodState == METHOD_DONE) SM_ENTER(EAP, SUCCESS); else if (sm->selectedMethod == EAP_TYPE_PEAP && sm->peap_done && sm->decision != DECISION_FAIL && sm->methodState == METHOD_DONE) SM_ENTER(EAP, SUCCESS); break; case EAP_RECEIVED: duplicate = (sm->reqId == sm->lastId) && sm->rxReq; if (sm->workaround && duplicate && os_memcmp(sm->req_md5, sm->last_md5, 16) != 0) { /* * RFC 4137 uses (reqId == lastId) as the only * verification for duplicate EAP requests. However, * this misses cases where the AS is incorrectly using * the same id again; and unfortunately, such * implementations exist. Use MD5 hash as an extra * verification for the packets being duplicate to * workaround these issues. */ wpa_printf(MSG_DEBUG, "EAP: AS used the same Id again," " but EAP packets were not identical"); wpa_printf(MSG_DEBUG, "EAP: workaround - assume this " "is not a duplicate packet"); duplicate = 0; } /* * Two special cases below for LEAP are local additions to work * around odd LEAP behavior (EAP-Success in the middle of * authentication and then swapped roles). Other transitions * are based on RFC 4137. */ if (sm->rxSuccess && sm->decision != DECISION_FAIL && (sm->reqId == sm->lastId || eap_success_workaround(sm, sm->reqId, sm->lastId))) SM_ENTER(EAP, SUCCESS); else if (sm->methodState != METHOD_CONT && ((sm->rxFailure && sm->decision != DECISION_UNCOND_SUCC) || (sm->rxSuccess && sm->decision == DECISION_FAIL && (sm->selectedMethod != EAP_TYPE_LEAP || sm->methodState != METHOD_MAY_CONT))) && (sm->reqId == sm->lastId || eap_success_workaround(sm, sm->reqId, sm->lastId))) SM_ENTER(EAP, FAILURE); else if (sm->rxReq && duplicate) SM_ENTER(EAP, RETRANSMIT); else if (sm->rxReq && !duplicate && sm->reqMethod == EAP_TYPE_NOTIFICATION && sm->allowNotifications) SM_ENTER(EAP, NOTIFICATION); else if (sm->rxReq && !duplicate && sm->selectedMethod == EAP_TYPE_NONE && sm->reqMethod == EAP_TYPE_IDENTITY) SM_ENTER(EAP, IDENTITY); else if (sm->rxReq && !duplicate && sm->selectedMethod == EAP_TYPE_NONE && sm->reqMethod != EAP_TYPE_IDENTITY && sm->reqMethod != EAP_TYPE_NOTIFICATION) SM_ENTER(EAP, GET_METHOD); else if (sm->rxReq && !duplicate && sm->reqMethod == sm->selectedMethod && sm->methodState != METHOD_DONE) SM_ENTER(EAP, METHOD); else if (sm->selectedMethod == EAP_TYPE_LEAP && (sm->rxSuccess || sm->rxResp)) SM_ENTER(EAP, METHOD); else SM_ENTER(EAP, DISCARD); break; case EAP_GET_METHOD: if (sm->selectedMethod == sm->reqMethod) SM_ENTER(EAP, METHOD); else SM_ENTER(EAP, SEND_RESPONSE); break; case EAP_METHOD: if (sm->ignore) SM_ENTER(EAP, DISCARD); else SM_ENTER(EAP, SEND_RESPONSE); break; case EAP_SEND_RESPONSE: SM_ENTER(EAP, IDLE); break; case EAP_DISCARD: SM_ENTER(EAP, IDLE); break; case EAP_IDENTITY: SM_ENTER(EAP, SEND_RESPONSE); break; case EAP_NOTIFICATION: SM_ENTER(EAP, SEND_RESPONSE); break; case EAP_RETRANSMIT: SM_ENTER(EAP, SEND_RESPONSE); break; case EAP_SUCCESS: break; case EAP_FAILURE: break; }}static Boolean eap_sm_allowMethod(struct eap_sm *sm, int vendor, EapType method){ struct wpa_ssid *config = eap_get_config(sm); if (!wpa_config_allowed_eap_method(config, vendor, method)) { wpa_printf(MSG_DEBUG, "EAP: configuration does not allow: " "vendor %u method %u", vendor, method); return FALSE; } if (eap_sm_get_eap_methods(vendor, method)) return TRUE; wpa_printf(MSG_DEBUG, "EAP: not included in build: " "vendor %u method %u", vendor, method); return FALSE;}static u8 * eap_sm_build_expanded_nak(struct eap_sm *sm, int id, size_t *len, const struct eap_method *methods, size_t count){ struct wpa_ssid *config = eap_get_config(sm); struct eap_hdr *resp; u8 *pos; int found = 0; const struct eap_method *m; wpa_printf(MSG_DEBUG, "EAP: Building expanded EAP-Nak"); /* RFC 3748 - 5.3.2: Expanded Nak */ *len = sizeof(struct eap_hdr) + 8; resp = os_malloc(*len + 8 * (count + 1)); if (resp == NULL) return NULL; resp->code = EAP_CODE_RESPONSE; resp->identifier = id; pos = (u8 *) (resp + 1); *pos++ = EAP_TYPE_EXPANDED; WPA_PUT_BE24(pos, EAP_VENDOR_IETF); pos += 3; WPA_PUT_BE32(pos, EAP_TYPE_NAK); pos += 4; for (m = methods; m; m = m->next) { if (sm->reqVendor == m->vendor && sm->reqVendorMethod == m->method) continue; /* do not allow the current method again */ if (wpa_config_allowed_eap_method(config, m->vendor, m->method)) { wpa_printf(MSG_DEBUG, "EAP: allowed type: " "vendor=%u method=%u", m->vendor, m->method); *pos++ = EAP_TYPE_EXPANDED; WPA_PUT_BE24(pos, m->vendor); pos += 3; WPA_PUT_BE32(pos, m->method); pos += 4; (*len) += 8; found++; } } if (!found) { wpa_printf(MSG_DEBUG, "EAP: no more allowed methods"); *pos++ = EAP_TYPE_EXPANDED; WPA_PUT_BE24(pos, EAP_VENDOR_IETF); pos += 3; WPA_PUT_BE32(pos, EAP_TYPE_NONE); pos += 4; (*len) += 8; } resp->length = host_to_be16(*len); return (u8 *) resp;}static u8 * eap_sm_buildNak(struct eap_sm *sm, int id, size_t *len){ struct wpa_ssid *config = eap_get_config(sm); struct eap_hdr *resp; u8 *pos; int found = 0, expanded_found = 0; size_t count; const struct eap_method *methods, *m; wpa_printf(MSG_DEBUG, "EAP: Building EAP-Nak (requested type %u " "vendor=%u method=%u not allowed)", sm->reqMethod, sm->reqVendor, sm->reqVendorMethod); methods = eap_peer_get_methods(&count); if (methods == NULL) return NULL; if (sm->reqMethod == EAP_TYPE_EXPANDED) return eap_sm_build_expanded_nak(sm, id, len, methods, count); /* RFC 3748 - 5.3.1: Legacy Nak */ *len = sizeof(struct eap_hdr) + 1; resp = os_malloc(*len + count + 1); if (resp == NULL) return NULL; resp->code = EAP_CODE_RESPONSE; resp->identifier = id; pos = (u8 *) (resp + 1); *pos++ = EAP_TYPE_NAK; for (m = methods; m; m = m->next) { if (m->vendor == EAP_VENDOR_IETF && m->method == sm->reqMethod) continue; /* do not allow the current method again */ if (wpa_config_allowed_eap_method(config, m->vendor, m->method)) { if (m->vendor != EAP_VENDOR_IETF) { if (expanded_found) continue; expanded_found = 1; *pos++ = EAP_TYPE_EXPANDED; } else *pos++ = m->method; (*len)++; found++; } } if (!found) { *pos = EAP_TYPE_NONE; (*len)++; } wpa_hexdump(MSG_DEBUG, "EAP: allowed methods", ((u8 *) (resp + 1)) + 1, found); resp->length = host_to_be16(*len); return (u8 *) resp;}static void eap_sm_processIdentity(struct eap_sm *sm, const u8 *req){ const struct eap_hdr *hdr = (const struct eap_hdr *) req; const u8 *pos = (const u8 *) (hdr + 1); pos++; wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_STARTED "EAP authentication started"); /* * RFC 3748 - 5.1: Identity * Data field may contain a displayable message in UTF-8. If this * includes NUL-character, only the data before that should be * displayed. Some EAP implementasitons may piggy-back additional * options after the NUL. */ /* TODO: could save displayable message so that it can be shown to the * user in case of interaction is required */ wpa_hexdump_ascii(MSG_DEBUG, "EAP: EAP-Request Identity data", pos, be_to_host16(hdr->length) - 5);}#ifdef PCSC_FUNCSstatic int eap_sm_imsi_identity(struct eap_sm *sm, struct wpa_ssid *ssid){ int aka = 0; char imsi[100]; size_t imsi_len; struct eap_method_type *m = ssid->eap_methods; int i; imsi_len = sizeof(imsi); if (scard_get_imsi(sm->scard_ctx, imsi, &imsi_len)) { wpa_printf(MSG_WARNING, "Failed to get IMSI from SIM"); return -1; } wpa_hexdump_ascii(MSG_DEBUG, "IMSI", (u8 *) imsi, imsi_len); for (i = 0; m && (m[i].vendor != EAP_VENDOR_IETF || m[i].method != EAP_TYPE_NONE); i++) { if (m[i].vendor == EAP_VENDOR_IETF && m[i].method == EAP_TYPE_AKA) { aka = 1; break; } } os_free(ssid->identity); ssid->identity = os_malloc(1 + imsi_len); if (ssid->identity == NULL) { wpa_printf(MSG_WARNING, "Failed to allocate buffer for " "IMSI-based identity"); return -1; } ssid->identity[0] = aka ? '0' : '1'; os_memcpy(ssid->identity + 1, imsi, imsi_len); ssid->identity_len = 1 + imsi_len; return 0;}#endif /* PCSC_FUNCS */static int eap_sm_get_scard_identity(struct eap_sm *sm, struct wpa_ssid *ssid){#ifdef PCSC_FUNCS if (scard_set_pin(sm->scard_ctx, ssid->pin)) { /* * Make sure the same PIN is not tried again in order to avoid * blocking SIM. */ os_free(ssid->pin); ssid->pin = NULL; wpa_printf(MSG_WARNING, "PIN validation failed"); eap_sm_request_pin(sm); return -1; } return eap_sm_imsi_identity(sm, ssid);#else /* PCSC_FUNCS */ return -1;#endif /* PCSC_FUNCS */}/** * eap_sm_buildIdentity - Build EAP-Identity/Response for the current network * @sm: Pointer to EAP state machine allocated with eap_sm_init() * @id: EAP identifier for the packet * @len: Pointer to a variable that will be set to the length of the response * @encrypted: Whether the packet is for encrypted tunnel (EAP phase 2) * Returns: Pointer to the allocated EAP-Identity/Response packet or %NULL on * failure * * This function allocates and builds an EAP-Identity/Response packet for the * current network. The caller is responsible for freeing the returned data. */u8 * eap_sm_buildIdentity(struct eap_sm *sm, int id, size_t *len, int encrypted){ struct wpa_ssid *config = eap_get_config(sm); struct eap_hdr *resp; u8 *pos; const u8 *identity; size_t identity_len; if (config == NULL) { wpa_printf(MSG_WARNING, "EAP: buildIdentity: configuration " "was not available"); return NULL; } if (sm->m && sm->m->get_identity && (identity = sm->m->get_identity(sm, sm->eap_method_priv, &identity_len)) != NULL) { wpa_hexdump_ascii(MSG_DEBUG, "EAP: using method re-auth " "identity", identity, identity_len); } else if (!encrypted && config->anonymous_identity) { identity = config->anonymous_identity; identity_len = config->anonymous_identity_len; wpa_hexdump_ascii(MSG_DEBUG, "EAP: using anonymous identity", identity, identity_len); } else { identity = config->identity; identity_len = config->identity_len; wpa_hexdump_ascii(MSG_DEBUG, "EAP: using real identity", identity, identity_len); } if (identity == NULL) { wpa_printf(MSG_WARNING, "EAP: buildIdentity: identity " "configuration was not available"); if (config->pcsc) { if (eap_sm_get_scard_identity(sm, config) < 0) return NULL; identity = config->identity; identity_len = config->identity_len; wpa_hexdump_ascii(MSG_DEBUG, "permanent identity from " "IMSI", identity, identity_len); } else { eap_sm_request_identity(sm); return NULL; } } *len = sizeof(struct eap_hdr) + 1 + identity_len; resp = os_malloc(*len); if (resp == NULL) return NULL; resp->code = EAP_CODE_RESPONSE; resp->identifier = id; resp->length = host_to_be16(*len); pos = (u8 *) (resp + 1); *pos++ = EAP_TYPE_IDENTITY; os_memcpy(pos, identity, identity_len); return (u8 *) resp;}static void eap_sm_processNotify(struct eap_sm *sm, const u8 *req){ const struct eap_hdr *hdr = (const struct eap_hdr *) req; const u8 *pos; char *msg; size_t i, msg_len; pos = (const u8 *) (hdr + 1); pos++; msg_len = be_to_host16(hdr->length); if (msg_len < 5) return; msg_len -= 5; wpa_hexdump_ascii(MSG_DEBUG, "EAP: EAP-Request Notification data", pos, msg_len); msg = os_malloc(msg_len + 1); if (msg == NULL) return; for (i = 0; i < msg_len; i++) msg[i] = isprint(pos[i]) ? (char) pos[i] : '_'; msg[msg_len] = '\0'; wpa_msg(sm->msg_ctx, MSG_INFO, "%s%s", WPA_EVENT_EAP_NOTIFICATION, msg); os_free(msg);}static u8 * eap_sm_buildNotify(int id, size_t *len){ struct eap_hdr *resp; u8 *pos; wpa_printf(MSG_DEBUG, "EAP: Generating EAP-Response Notification"); *len = sizeof(struct eap_hdr) + 1; resp = os_malloc(*len); if (resp == NULL) return NULL; resp->code = EAP_CODE_RESPONSE; resp->identifier = id; resp->length = host_to_be16(*len); pos = (u8 *) (resp + 1); *pos = EAP_TYPE_NOTIFICATION; return (u8 *) resp;}static void eap_sm_parseEapReq(struct eap_sm *sm, const u8 *req, size_t len){ const struct eap_hdr *hdr; size_t plen; const u8 *pos; sm->rxReq = sm->rxResp = sm->rxSuccess = sm->rxFailure = FALSE; sm->reqId = 0; sm->reqMethod = EAP_TYPE_NONE; sm->reqVendor = EAP_VENDOR_IETF; sm->reqVendorMethod = EAP_TYPE_NONE; if (req == NULL || len < sizeof(*hdr)) return; hdr = (const struct eap_hdr *) req; plen = be_to_host16(hdr->length); if (plen > len) { wpa_printf(MSG_DEBUG, "EAP: Ignored truncated EAP-Packet "
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -