📄 wpa.c
字号:
break; } sm->PTK_valid = FALSE; memset(&sm->PTK, 0, sizeof(sm->PTK)); if (event != WPA_REAUTH_EAPOL) { sm->pairwise_set = FALSE; hostapd_set_encryption(sm->hapd, "none", sm->sta->addr, 0, (u8 *) "", 0); } wpa_sm_step(sm);}static const char * wpa_alg_txt(int alg){ switch (alg) { case WPA_CIPHER_CCMP: return "CCMP"; case WPA_CIPHER_TKIP: return "TKIP"; case WPA_CIPHER_WEP104: case WPA_CIPHER_WEP40: return "WEP"; default: return ""; }}/* Definitions for clarifying state machine implementation */#define SM_STATE(machine, state) \static void sm_ ## machine ## _ ## state ## _Enter(struct wpa_state_machine \*sm)#define SM_ENTRY(machine, _state, _data) \sm->changed = TRUE; \sm->_data ## _ ## state = machine ## _ ## _state; \if (sm->hapd->conf->debug >= HOSTAPD_DEBUG_MINIMAL) \ printf("WPA: " MACSTR " " #machine " entering state " #_state \ "\n", MAC2STR(sm->sta->addr));#define SM_ENTER(machine, state) sm_ ## machine ## _ ## state ## _Enter(sm)#define SM_STEP(machine) \static void sm_ ## machine ## _Step(struct wpa_state_machine *sm)#define SM_STEP_RUN(machine) sm_ ## machine ## _Step(sm)SM_STATE(WPA_PTK, INITIALIZE){ struct hostapd_data *hapd = sm->hapd; SM_ENTRY(WPA_PTK, INITIALIZE, wpa_ptk); if (sm->Init) { /* Init flag is not cleared here, so avoid busy * loop by claiming nothing changed. */ sm->changed = FALSE; } sm->keycount = 0; if (sm->GUpdateStationKeys) hapd->wpa_auth->GKeyDoneStations--; sm->GUpdateStationKeys = FALSE; if (sm->sta->wpa == WPA_VERSION_WPA) sm->PInitAKeys = FALSE; if (1 /* Unicast cipher supported AND (ESS OR ((IBSS or WDS) and * Local AA > Remote AA)) */) { sm->Pair = TRUE; } ieee802_1x_notify_port_enabled(sm->sta->eapol_sm, 0); hostapd_set_encryption(sm->hapd, "none", sm->sta->addr, 0, (u8 *) "", 0); sm->pairwise_set = FALSE; sm->PTK_valid = FALSE; memset(&sm->PTK, 0, sizeof(sm->PTK)); ieee802_1x_notify_port_valid(sm->sta->eapol_sm, 0); sm->TimeoutCtr = 0; if (sm->sta->wpa_key_mgmt == WPA_KEY_MGMT_PSK) ieee802_1x_set_sta_authorized(sm->hapd, sm->sta, 0);}SM_STATE(WPA_PTK, DISCONNECT){ SM_ENTRY(WPA_PTK, DISCONNECT, wpa_ptk); sm->Disconnect = FALSE; wpa_sta_disconnect(sm->hapd, sm->sta);}SM_STATE(WPA_PTK, DISCONNECTED){ SM_ENTRY(WPA_PTK, DISCONNECTED, wpa_ptk); sm->hapd->wpa_auth->GNoStations--; sm->DeauthenticationRequest = FALSE;}SM_STATE(WPA_PTK, AUTHENTICATION){ SM_ENTRY(WPA_PTK, AUTHENTICATION, wpa_ptk); sm->hapd->wpa_auth->GNoStations++; memset(&sm->PTK, 0, sizeof(sm->PTK)); sm->PTK_valid = FALSE; if (sm->sta->eapol_sm) { sm->sta->eapol_sm->portControl = Auto; sm->sta->eapol_sm->portEnabled = TRUE; } sm->AuthenticationRequest = FALSE;}SM_STATE(WPA_PTK, AUTHENTICATION2){ SM_ENTRY(WPA_PTK, AUTHENTICATION2, wpa_ptk); memcpy(sm->ANonce, sm->hapd->wpa_auth->Counter, WPA_NONCE_LEN); inc_byte_array(sm->hapd->wpa_auth->Counter, WPA_NONCE_LEN); sm->ReAuthenticationRequest = FALSE; /* IEEE 802.11i/D9.0 does not clear TimeoutCtr here, but this is more * logical place than INITIALIZE since AUTHENTICATION2 can be * re-entered on ReAuthenticationRequest without going through * INITIALIZE. */ sm->TimeoutCtr = 0;}SM_STATE(WPA_PTK, INITPMK){ u8 *key; size_t len; SM_ENTRY(WPA_PTK, INITPMK, wpa_ptk); if (sm->sta->pmksa) { wpa_printf(MSG_DEBUG, "WPA: PMK from PMKSA cache"); memcpy(sm->PMK, sm->sta->pmksa->pmk, WPA_PMK_LEN); } else if ((key = ieee802_1x_get_key_crypt(sm->sta->eapol_sm, &len))) { wpa_printf(MSG_DEBUG, "WPA: PMK from EAPOL state machine " "(len=%lu)", (unsigned long) len); if (len > WPA_PMK_LEN) len = WPA_PMK_LEN; memcpy(sm->PMK, key, len); } else { wpa_printf(MSG_DEBUG, "WPA: Could not get PMK"); } sm->sta->req_replay_counter_used = 0; /* IEEE 802.11i/D9.0 does not set keyRun to FALSE, but not doing this * will break reauthentication since EAPOL state machines may not be * get into AUTHENTICATING state that clears keyRun before WPA state * machine enters AUTHENTICATION2 state and goes immediately to INITPMK * state and takes PMK from the previously used AAA Key. This will * eventually fail in 4-Way Handshake because Supplicant uses PMK * derived from the new AAA Key. Setting keyRun = FALSE here seems to * be good workaround for this issue. */ if (sm->sta->eapol_sm) sm->sta->eapol_sm->keyRun = FALSE;}SM_STATE(WPA_PTK, INITPSK){ const u8 *psk; SM_ENTRY(WPA_PTK, INITPSK, wpa_ptk); psk = hostapd_get_psk(sm->hapd->conf, sm->sta->addr, NULL); if (psk) memcpy(sm->PMK, psk, WPA_PMK_LEN); sm->sta->req_replay_counter_used = 0;}SM_STATE(WPA_PTK, PTKSTART){ u8 *pmkid = NULL; size_t pmkid_len = 0; SM_ENTRY(WPA_PTK, PTKSTART, wpa_ptk); sm->PTKRequest = FALSE; sm->TimeoutEvt = FALSE; hostapd_logger(sm->hapd, sm->sta->addr, HOSTAPD_MODULE_WPA, HOSTAPD_LEVEL_DEBUG, "sending 1/4 msg of 4-Way Handshake"); if (sm->sta->pmksa && (pmkid = malloc(2 + RSN_SELECTOR_LEN + PMKID_LEN))) { pmkid_len = 2 + RSN_SELECTOR_LEN + PMKID_LEN; pmkid[0] = WLAN_EID_GENERIC; pmkid[1] = RSN_SELECTOR_LEN + PMKID_LEN; memcpy(&pmkid[2], RSN_KEY_DATA_PMKID, RSN_SELECTOR_LEN); memcpy(&pmkid[2 + RSN_SELECTOR_LEN], sm->sta->pmksa->pmkid, PMKID_LEN); } wpa_send_eapol(sm->hapd, sm->sta, 0, 0, 1, 0, 1, NULL, sm->ANonce, pmkid, pmkid_len, NULL, 0, 0); free(pmkid); sm->TimeoutCtr++;}SM_STATE(WPA_PTK, PTKCALCNEGOTIATING){ struct wpa_ptk PTK; int ok = 0; const u8 *pmk = NULL; SM_ENTRY(WPA_PTK, PTKCALCNEGOTIATING, wpa_ptk); sm->EAPOLKeyReceived = FALSE; /* WPA with IEEE 802.1X: use the derived PMK from EAP * WPA-PSK: iterate through possible PSKs and select the one matching * the packet */ for (;;) { if (sm->sta->wpa_key_mgmt == WPA_KEY_MGMT_PSK) { pmk = hostapd_get_psk(sm->hapd->conf, sm->sta->addr, pmk); if (pmk == NULL) break; } else pmk = sm->PMK; wpa_pmk_to_ptk(sm->hapd, pmk, sm->hapd->own_addr, sm->sta->addr, sm->ANonce, sm->SNonce, (u8 *) &PTK, sizeof(PTK)); if (wpa_verify_key_mic(&PTK, sm->last_rx_eapol_key, sm->last_rx_eapol_key_len) == 0) { ok = 1; break; } if (sm->sta->wpa_key_mgmt != WPA_KEY_MGMT_PSK) break; } if (!ok) { hostapd_logger(sm->hapd, sm->sta->addr, HOSTAPD_MODULE_WPA, HOSTAPD_LEVEL_DEBUG, "invalid MIC in msg 2/4 " "of 4-Way Handshake"); return; } eloop_cancel_timeout(wpa_send_eapol_timeout, sm->hapd, sm->sta); if (sm->sta->wpa_key_mgmt == WPA_KEY_MGMT_PSK) { /* PSK may have changed from the previous choice, so update * state machine data based on whatever PSK was selected here. */ memcpy(sm->PMK, pmk, WPA_PMK_LEN); } sm->MICVerified = TRUE; memcpy(&sm->PTK, &PTK, sizeof(PTK)); sm->PTK_valid = TRUE;}SM_STATE(WPA_PTK, PTKCALCNEGOTIATING2){ SM_ENTRY(WPA_PTK, PTKCALCNEGOTIATING2, wpa_ptk); sm->TimeoutCtr = 0;}SM_STATE(WPA_PTK, PTKINITNEGOTIATING){ u8 rsc[WPA_KEY_RSC_LEN]; struct wpa_authenticator *gsm = sm->hapd->wpa_auth; u8 *wpa_ie; int wpa_ie_len; SM_ENTRY(WPA_PTK, PTKINITNEGOTIATING, wpa_ptk); sm->TimeoutEvt = FALSE; /* Send EAPOL(1, 1, 1, Pair, P, RSC, ANonce, MIC(PTK), RSNIE, GTK[GN]) */ memset(rsc, 0, WPA_KEY_RSC_LEN); hostapd_get_seqnum(sm->hapd, NULL, gsm->GN, rsc); wpa_ie = sm->hapd->wpa_ie; wpa_ie_len = sm->hapd->wpa_ie_len; if (sm->sta->wpa == WPA_VERSION_WPA && (sm->hapd->conf->wpa & HOSTAPD_WPA_VERSION_WPA2) && wpa_ie_len > wpa_ie[1] + 2 && wpa_ie[0] == WLAN_EID_RSN) { /* WPA-only STA, remove RSN IE */ wpa_ie = wpa_ie + wpa_ie[1] + 2; wpa_ie_len = wpa_ie[1] + 2; } hostapd_logger(sm->hapd, sm->sta->addr, HOSTAPD_MODULE_WPA, HOSTAPD_LEVEL_DEBUG, "sending 3/4 msg of 4-Way Handshake"); wpa_send_eapol(sm->hapd, sm->sta, sm->sta->wpa == WPA_VERSION_WPA2 ? 1 : 0, 1, 1, 1, 1, rsc, sm->ANonce, wpa_ie, wpa_ie_len, gsm->GTK[gsm->GN - 1], gsm->GTK_len, gsm->GN); sm->TimeoutCtr++;}SM_STATE(WPA_PTK, PTKINITDONE){ SM_ENTRY(WPA_PTK, PTKINITDONE, wpa_ptk); sm->EAPOLKeyReceived = FALSE; if (sm->Pair) { char *alg; int klen; if (sm->sta->pairwise == WPA_CIPHER_TKIP) { alg = "TKIP"; klen = 32; } else { alg = "CCMP"; klen = 16; } if (hostapd_set_encryption(sm->hapd, alg, sm->sta->addr, 0, sm->PTK.tk1, klen)) { wpa_sta_disconnect(sm->hapd, sm->sta); return; } /* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */ sm->pairwise_set = TRUE; if (sm->sta->wpa_key_mgmt == WPA_KEY_MGMT_PSK) ieee802_1x_set_sta_authorized(sm->hapd, sm->sta, 1); } if (0 /* IBSS == TRUE */) { sm->keycount++; if (sm->keycount == 2) { ieee802_1x_notify_port_valid(sm->sta->eapol_sm, 1); } } else { ieee802_1x_notify_port_valid(sm->sta->eapol_sm, 1); } if (sm->sta->eapol_sm) { sm->sta->eapol_sm->keyAvailable = FALSE; sm->sta->eapol_sm->keyDone = TRUE; } if (sm->sta->wpa == WPA_VERSION_WPA) sm->PInitAKeys = TRUE; else sm->has_GTK = TRUE; hostapd_logger(sm->hapd, sm->sta->addr, HOSTAPD_MODULE_WPA, HOSTAPD_LEVEL_INFO, "pairwise key handshake completed " "(%s)", sm->sta->wpa == WPA_VERSION_WPA ? "WPA" : "RSN");}SM_STEP(WPA_PTK){ struct wpa_authenticator *wpa_auth = sm->hapd->wpa_auth; if (sm->Init) SM_ENTER(WPA_PTK, INITIALIZE); else if (sm->Disconnect /* || FIX: dot11RSNAConfigSALifetime timeout */) SM_ENTER(WPA_PTK, DISCONNECT); else if (sm->DeauthenticationRequest) SM_ENTER(WPA_PTK, DISCONNECTED); else if (sm->AuthenticationRequest) SM_ENTER(WPA_PTK, AUTHENTICATION); else if (sm->ReAuthenticationRequest) SM_ENTER(WPA_PTK, AUTHENTICATION2); else if (sm->PTKRequest) SM_ENTER(WPA_PTK, PTKSTART); else switch (sm->wpa_ptk_state) { case WPA_PTK_INITIALIZE: break; case WPA_PTK_DISCONNECT: SM_ENTER(WPA_PTK, DISCONNECTED); break; case WPA_PTK_DISCONNECTED: SM_ENTER(WPA_PTK, INITIALIZE); break; case WPA_PTK_AUTHENTICATION: SM_ENTER(WPA_PTK, AUTHENTICATION2); break; case WPA_PTK_AUTHENTICATION2: if ((sm->sta->wpa_key_mgmt == WPA_KEY_MGMT_IEEE8021X) && sm->sta->eapol_sm && sm->sta->eapol_sm->keyRun) SM_ENTER(WPA_PTK, INITPMK); else if ((sm->sta->wpa_key_mgmt == WPA_KEY_MGMT_PSK) /* FIX: && 802.1X::keyRun */) SM_ENTER(WPA_PTK, INITPSK); break; case WPA_PTK_INITPMK: if (sm->sta->eapol_sm && sm->sta->eapol_sm->keyAvailable) SM_ENTER(WPA_PTK, PTKSTART); else { wpa_auth->dot11RSNA4WayHandshakeFailures++; SM_ENTER(WPA_PTK, DISCONNECT); } break; case WPA_PTK_INITPSK: if (hostapd_get_psk(sm->hapd->conf, sm->sta->addr, NULL)) SM_ENTER(WPA_PTK, PTKSTART); else { hostapd_logger(sm->hapd, sm->sta->addr, HOSTAPD_MODULE_WPA, HOSTAPD_LEVEL_INFO, "no PSK configured for the STA"); wpa_auth->dot11RSNA4WayHandshakeFailures++; SM_ENTER(WPA_PTK, DISCONNECT); } break; case WPA_PTK_PTKSTART: if (sm->EAPOLKeyReceived && !sm->EAPOLKeyRequest && sm->EAPOLKeyPairwise) SM_ENTER(WPA_PTK, PTKCALCNEGOTIATING); else if (sm->TimeoutCtr > dot11RSNAConfigPairwiseUpdateCount) { wpa_auth->dot11RSNA4WayHandshakeFailures++; SM_ENTER(WPA_PTK, DISCONNECT); } else if (sm->TimeoutEvt) SM_ENTER(WPA_PTK, PTKSTART); break; case WPA_PTK_PTKCALCNEGOTIATING: if (sm->MICVerified) SM_ENTER(WPA_PTK, PTKCALCNEGOTIATING2); else if (sm->EAPOLKeyReceived && !sm->EAPOLKeyRequest && sm->EAPOLKeyPairwise) SM_ENTER(WPA_PTK, PTKCALCNEGOTIATING); else if (sm->TimeoutEvt) SM_ENTER(WPA_PTK, PTKSTART); break; case WPA_PTK_PTKCALCNEGOTIATING2: SM_ENTER(WPA_PTK, PTKINITNEGOTIATING); break; case WPA_PTK_PTKINITNEGOTIATING: if (sm->EAPOLKeyReceived && !sm->EAPOLKeyRequest && sm->EAPOLKeyPairwise && sm->MICVerified) SM_ENTER(WPA_PTK, PTKINITDONE); else if (sm->TimeoutCtr > dot11RSNAConfigPairwiseUpdateCount) { wpa_auth->dot11RSNA4WayHandshakeFailures++; SM_ENTER(WPA_PTK, DISCONNECT); } else if (sm->TimeoutEvt) SM_ENTER(WPA_PTK, PTKINITNEGOTIATING); break; case WPA_PTK_PTKINITDONE: break; }}SM_STATE(WPA_PTK_GROUP, IDLE){ SM_ENTRY(WPA_PTK_GROUP, IDLE, wpa_ptk_group); if (sm->Init) { /* Init flag is not cleared here, so avoid busy * loop by claiming nothing changed. */ sm->changed = FALSE; } sm->GTimeoutCtr = 0;}SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING){ u8 rsc[WPA_KEY_RSC_LEN]; struct wpa_authenticator *gsm = sm->hapd->wpa_auth; SM_ENTRY(WPA_PTK_GROUP, REKEYNEGOTIATING, wpa_ptk_group); if (sm->sta->wpa == WPA_VERSION_WPA) sm->PInitAKeys = FALSE; sm->TimeoutEvt = FALSE; /* Send EAPOL(1, 1, 1, !Pair, G, RSC, GNonce, MIC(PTK), GTK[GN]) */ memset(rsc, 0, WPA_KEY_RSC_LEN); if (gsm->wpa_group_state == WPA_GROUP_SETKEYSDONE) hostapd_get_seqnum(sm->hapd, NULL, gsm->GN, rsc); hostapd_logger(sm->hapd, sm->sta->addr, HOSTAPD_MODULE_WPA, HOSTAPD_LEVEL_DEBUG, "sending 1/2 msg of Group Key Handshake"); wpa_send_eapol(sm->hapd, sm->sta, 1, 1, 1, !sm->Pair, 0, rsc, gsm->GNonce, NULL, 0, gsm->GTK[gsm->GN - 1], gsm->GTK_len, gsm->GN); sm->GTimeoutCtr++;}SM_STATE(WPA_PTK_GROUP, REKEYESTABLISHED){ SM_ENTRY(WPA_PTK_GROUP, REKEYESTABLISHED, wpa_ptk_group); sm->EAPOLKeyReceived = FALSE; sm->GUpdateStationKeys = FALSE; sm->hapd->wpa_auth->GKeyDoneStations--; sm->GTimeoutCtr = 0; /* FIX: MLME.SetProtection.Request(TA, Tx_Rx) */ hos
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -