📄 wpa.c
字号:
case WPA_KEY_INFO_TYPE_HMAC_MD5_RC4: hmac_md5(key, 16, data, len, mic); break; case WPA_KEY_INFO_TYPE_HMAC_SHA1_AES: hmac_sha1(key, 16, data, len, hash); memcpy(mic, hash, MD5_MAC_LEN); break; default: return -1; } return 0;}static void __wpa_send_eapol(struct wpa_authenticator *wpa_auth, struct wpa_state_machine *sm, int secure, int mic, int ack, int install, int pairwise, u8 *key_rsc, u8 *nonce, u8 *ie, size_t ie_len, u8 *gtk, size_t gtk_len, int keyidx, int encr, int force_version){ struct ieee802_1x_hdr *hdr; struct wpa_eapol_key *key; size_t len; int key_info, alg; int key_data_len, pad_len = 0; u8 *buf, *pos; int version; len = sizeof(struct ieee802_1x_hdr) + sizeof(struct wpa_eapol_key); if (force_version) version = force_version; else if (sm->pairwise == WPA_CIPHER_CCMP) version = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES; else version = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4; wpa_printf(MSG_DEBUG, "WPA: Send EAPOL(secure=%d mic=%d ack=%d " "install=%d pairwise=%d ie_len=%lu gtk_len=%lu keyidx=%d " "encr=%d)", secure, mic, ack, install, pairwise, (unsigned long) ie_len, (unsigned long) gtk_len, keyidx, encr); key_data_len = ie_len + gtk_len; if (sm->wpa == WPA_VERSION_WPA2 && gtk_len) key_data_len += 2 + RSN_SELECTOR_LEN + 2; if (version == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) { pad_len = key_data_len % 8; if (pad_len) pad_len = 8 - pad_len; key_data_len += pad_len + 8; } len += key_data_len; hdr = wpa_zalloc(len); if (hdr == NULL) return; hdr->version = wpa_auth->conf.eapol_version; hdr->type = IEEE802_1X_TYPE_EAPOL_KEY; hdr->length = htons(len - sizeof(*hdr)); key = (struct wpa_eapol_key *) (hdr + 1); key->type = sm->wpa == WPA_VERSION_WPA2 ? EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA; key_info = version; if (secure) key_info |= WPA_KEY_INFO_SECURE; if (mic) key_info |= WPA_KEY_INFO_MIC; if (ack) key_info |= WPA_KEY_INFO_ACK; if (install) key_info |= WPA_KEY_INFO_INSTALL; if (pairwise) key_info |= WPA_KEY_INFO_KEY_TYPE; if (encr && sm->wpa == WPA_VERSION_WPA2) key_info |= WPA_KEY_INFO_ENCR_KEY_DATA; if (sm->wpa != WPA_VERSION_WPA2) key_info |= keyidx << WPA_KEY_INFO_KEY_INDEX_SHIFT; key->key_info = htons(key_info); alg = pairwise ? sm->pairwise : wpa_auth->conf.wpa_group; switch (alg) { case WPA_CIPHER_CCMP: key->key_length = htons(16); break; case WPA_CIPHER_TKIP: key->key_length = htons(32); break; case WPA_CIPHER_WEP40: key->key_length = htons(5); break; case WPA_CIPHER_WEP104: key->key_length = htons(13); break; } inc_byte_array(sm->key_replay_counter, WPA_REPLAY_COUNTER_LEN); memcpy(key->replay_counter, sm->key_replay_counter, WPA_REPLAY_COUNTER_LEN); sm->key_replay_counter_valid = TRUE; if (nonce) memcpy(key->key_nonce, nonce, WPA_NONCE_LEN); if (key_rsc) memcpy(key->key_rsc, key_rsc, WPA_KEY_RSC_LEN); if (ie && !encr) { memcpy(key + 1, ie, ie_len); key->key_data_length = htons(ie_len); } else if (encr && (gtk || ie)) { buf = wpa_zalloc(key_data_len); if (buf == NULL) { free(hdr); return; } pos = buf; if (ie) { memcpy(pos, ie, ie_len); pos += ie_len; } if (gtk) { if (sm->wpa == WPA_VERSION_WPA2) { *pos++ = WLAN_EID_GENERIC; *pos++ = RSN_SELECTOR_LEN + 2 + gtk_len; memcpy(pos, RSN_KEY_DATA_GROUPKEY, RSN_SELECTOR_LEN); pos += RSN_SELECTOR_LEN; *pos++ = keyidx & 0x03; *pos++ = 0; } memcpy(pos, gtk, gtk_len); pos += gtk_len; } if (pad_len) *pos++ = 0xdd; wpa_hexdump_key(MSG_DEBUG, "Plaintext EAPOL-Key Key Data", buf, key_data_len); if (version == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) { aes_wrap(sm->PTK.encr_key, (key_data_len - 8) / 8, buf, (u8 *) (key + 1)); key->key_data_length = htons(key_data_len); } else { u8 ek[32]; memcpy(key->key_iv, wpa_auth->Counter + WPA_NONCE_LEN - 16, 16); inc_byte_array(wpa_auth->Counter, WPA_NONCE_LEN); memcpy(ek, key->key_iv, 16); memcpy(ek + 16, sm->PTK.encr_key, 16); memcpy(key + 1, buf, key_data_len); rc4_skip(ek, 32, 256, (u8 *) (key + 1), key_data_len); key->key_data_length = htons(key_data_len); } free(buf); } if (mic) { if (!sm->PTK_valid) { wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG, "PTK not valid when sending EAPOL-Key " "frame"); free(hdr); return; } wpa_calc_eapol_key_mic(version, sm->PTK.mic_key, (u8 *) hdr, len, key->key_mic); } wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_inc_EapolFramesTx, 1); wpa_auth_send_eapol(wpa_auth, sm->addr, (u8 *) hdr, len, sm->pairwise_set); free(hdr);}static void wpa_send_eapol(struct wpa_authenticator *wpa_auth, struct wpa_state_machine *sm, int secure, int mic, int ack, int install, int pairwise, u8 *key_rsc, u8 *nonce, u8 *ie, size_t ie_len, u8 *gtk, size_t gtk_len, int keyidx){ int timeout_ms; if (sm == NULL) return; __wpa_send_eapol(wpa_auth, sm, secure, mic, ack, install, pairwise, key_rsc, nonce, ie, ie_len, gtk, gtk_len, keyidx, gtk ? 1 : 0, 0); timeout_ms = pairwise ? dot11RSNAConfigPairwiseUpdateTimeOut : dot11RSNAConfigGroupUpdateTimeOut; eloop_register_timeout(timeout_ms / 1000, (timeout_ms % 1000) * 1000, wpa_send_eapol_timeout, wpa_auth, sm);}static int wpa_verify_key_mic(struct wpa_ptk *PTK, u8 *data, size_t data_len){ struct ieee802_1x_hdr *hdr; struct wpa_eapol_key *key; u16 key_info; int type, ret = 0; u8 mic[16]; if (data_len < sizeof(*hdr) + sizeof(*key)) return -1; hdr = (struct ieee802_1x_hdr *) data; key = (struct wpa_eapol_key *) (hdr + 1); key_info = ntohs(key->key_info); type = key_info & WPA_KEY_INFO_TYPE_MASK; memcpy(mic, key->key_mic, 16); memset(key->key_mic, 0, 16); if (wpa_calc_eapol_key_mic(key_info & WPA_KEY_INFO_TYPE_MASK, PTK->mic_key, data, data_len, key->key_mic) || memcmp(mic, key->key_mic, 16) != 0) ret = -1; memcpy(key->key_mic, mic, 16); return ret;}void wpa_auth_sm_event(struct wpa_state_machine *sm, wpa_event event){ if (sm == NULL) return; wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, "event %d notification", event); switch (event) { case WPA_AUTH: case WPA_ASSOC: break; case WPA_DEAUTH: case WPA_DISASSOC: sm->DeauthenticationRequest = TRUE; break; case WPA_REAUTH: case WPA_REAUTH_EAPOL: sm->ReAuthenticationRequest = TRUE; break; } sm->PTK_valid = FALSE; memset(&sm->PTK, 0, sizeof(sm->PTK)); if (event != WPA_REAUTH_EAPOL) { sm->pairwise_set = FALSE; wpa_auth_set_key(sm->wpa_auth, "none", sm->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 ""; }}SM_STATE(WPA_PTK, INITIALIZE){ SM_ENTRY_MA(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) sm->wpa_auth->GKeyDoneStations--; sm->GUpdateStationKeys = FALSE; if (sm->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; } wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portEnabled, 0); wpa_auth_set_key(sm->wpa_auth, "none", sm->addr, 0, (u8 *) "", 0); sm->pairwise_set = FALSE; sm->PTK_valid = FALSE; memset(&sm->PTK, 0, sizeof(sm->PTK)); wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portValid, 0); sm->TimeoutCtr = 0; if (sm->wpa_key_mgmt == WPA_KEY_MGMT_PSK) { wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_authorized, 0); }}SM_STATE(WPA_PTK, DISCONNECT){ SM_ENTRY_MA(WPA_PTK, DISCONNECT, wpa_ptk); sm->Disconnect = FALSE; wpa_sta_disconnect(sm->wpa_auth, sm->addr);}SM_STATE(WPA_PTK, DISCONNECTED){ SM_ENTRY_MA(WPA_PTK, DISCONNECTED, wpa_ptk); sm->wpa_auth->GNoStations--; sm->DeauthenticationRequest = FALSE;}SM_STATE(WPA_PTK, AUTHENTICATION){ SM_ENTRY_MA(WPA_PTK, AUTHENTICATION, wpa_ptk); sm->wpa_auth->GNoStations++; memset(&sm->PTK, 0, sizeof(sm->PTK)); sm->PTK_valid = FALSE; wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portControl_Auto, 1); wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portEnabled, 1); sm->AuthenticationRequest = FALSE;}SM_STATE(WPA_PTK, AUTHENTICATION2){ SM_ENTRY_MA(WPA_PTK, AUTHENTICATION2, wpa_ptk); memcpy(sm->ANonce, sm->wpa_auth->Counter, WPA_NONCE_LEN); inc_byte_array(sm->wpa_auth->Counter, WPA_NONCE_LEN); sm->ReAuthenticationRequest = FALSE; /* IEEE 802.11i 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){ size_t len = WPA_PMK_LEN; SM_ENTRY_MA(WPA_PTK, INITPMK, wpa_ptk); if (sm->pmksa) { wpa_printf(MSG_DEBUG, "WPA: PMK from PMKSA cache"); memcpy(sm->PMK, sm->pmksa->pmk, WPA_PMK_LEN); } else if (wpa_auth_get_pmk(sm->wpa_auth, sm->addr, sm->PMK, &len) == 0) { wpa_printf(MSG_DEBUG, "WPA: PMK from EAPOL state machine " "(len=%lu)", (unsigned long) len); } else { wpa_printf(MSG_DEBUG, "WPA: Could not get PMK"); } sm->req_replay_counter_used = 0; /* IEEE 802.11i 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. */ wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_keyRun, 0);}SM_STATE(WPA_PTK, INITPSK){ const u8 *psk; SM_ENTRY_MA(WPA_PTK, INITPSK, wpa_ptk); psk = wpa_auth_get_psk(sm->wpa_auth, sm->addr, NULL); if (psk) memcpy(sm->PMK, psk, WPA_PMK_LEN); sm->req_replay_counter_used = 0;}SM_STATE(WPA_PTK, PTKSTART){ u8 *pmkid = NULL; size_t pmkid_len = 0; SM_ENTRY_MA(WPA_PTK, PTKSTART, wpa_ptk); sm->PTKRequest = FALSE; sm->TimeoutEvt = FALSE; wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, "sending 1/4 msg of 4-Way Handshake"); if (sm->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->pmksa->pmkid, PMKID_LEN); } wpa_send_eapol(sm->wpa_auth, sm, 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_MA(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->wpa_key_mgmt == WPA_KEY_MGMT_PSK) { pmk = wpa_auth_get_psk(sm->wpa_auth, sm->addr, pmk); if (pmk == NULL) break; } else pmk = sm->PMK; wpa_pmk_to_ptk(pmk, sm->wpa_auth->addr, sm->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->wpa_key_mgmt != WPA_KEY_MGMT_PSK) break; } if (!ok) { wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, "invalid MIC in msg 2/4 of 4-Way Handshake"); return; } eloop_cancel_timeout(wpa_send_eapol_timeout, sm->wpa_auth, sm); if (sm->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_MA(WPA_PTK, PTKCALCNEGOTIATING2, wpa_ptk); sm->TimeoutCt
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -