📄 wpa.c
字号:
if (sm->ft_completed) { wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG, "FT authentication already completed - do not " "start 4-way handshake"); return; }#endif /* CONFIG_IEEE80211R */ if (sm->started) { os_memset(&sm->key_replay, 0, sizeof(sm->key_replay)); sm->ReAuthenticationRequest = TRUE; wpa_sm_step(sm); return; } wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG, "start authentication"); sm->started = 1; sm->Init = TRUE; wpa_sm_step(sm); sm->Init = FALSE; sm->AuthenticationRequest = TRUE; wpa_sm_step(sm);}void wpa_auth_sta_no_wpa(struct wpa_state_machine *sm){ /* WPA/RSN was not used - clear WPA state. This is needed if the STA * reassociates back to the same AP while the previous entry for the * STA has not yet been removed. */ if (sm == NULL) return; sm->wpa_key_mgmt = 0;}static void wpa_free_sta_sm(struct wpa_state_machine *sm){ os_free(sm->last_rx_eapol_key); os_free(sm->wpa_ie); os_free(sm);}void wpa_auth_sta_deinit(struct wpa_state_machine *sm){ if (sm == NULL) return; if (sm->wpa_auth->conf.wpa_strict_rekey && sm->has_GTK) { wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, "strict rekeying - force GTK rekey since STA " "is leaving"); eloop_cancel_timeout(wpa_rekey_gtk, sm->wpa_auth, NULL); eloop_register_timeout(0, 500000, wpa_rekey_gtk, sm->wpa_auth, NULL); } eloop_cancel_timeout(wpa_send_eapol_timeout, sm->wpa_auth, sm); eloop_cancel_timeout(wpa_sm_call_step, sm, NULL); eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm); if (sm->in_step_loop) { /* Must not free state machine while wpa_sm_step() is running. * Freeing will be completed in the end of wpa_sm_step(). */ wpa_printf(MSG_DEBUG, "WPA: Registering pending STA state " "machine deinit for " MACSTR, MAC2STR(sm->addr)); sm->pending_deinit = 1; } else wpa_free_sta_sm(sm);}static void wpa_request_new_ptk(struct wpa_state_machine *sm){ if (sm == NULL) return; sm->PTKRequest = TRUE; sm->PTK_valid = 0;}static int wpa_replay_counter_valid(struct wpa_state_machine *sm, const u8 *replay_counter){ int i; for (i = 0; i < RSNA_MAX_EAPOL_RETRIES; i++) { if (!sm->key_replay[i].valid) break; if (os_memcmp(replay_counter, sm->key_replay[i].counter, WPA_REPLAY_COUNTER_LEN) == 0) return 1; } return 0;}void wpa_receive(struct wpa_authenticator *wpa_auth, struct wpa_state_machine *sm, u8 *data, size_t data_len){ struct ieee802_1x_hdr *hdr; struct wpa_eapol_key *key; u16 key_info, key_data_length; enum { PAIRWISE_2, PAIRWISE_4, GROUP_2, REQUEST, SMK_M1, SMK_M3, SMK_ERROR } msg; char *msgtxt; struct wpa_eapol_ie_parse kde; if (wpa_auth == NULL || !wpa_auth->conf.wpa || sm == NULL) return; if (data_len < sizeof(*hdr) + sizeof(*key)) return; hdr = (struct ieee802_1x_hdr *) data; key = (struct wpa_eapol_key *) (hdr + 1); key_info = WPA_GET_BE16(key->key_info); key_data_length = WPA_GET_BE16(key->key_data_length); if (key_data_length > data_len - sizeof(*hdr) - sizeof(*key)) { wpa_printf(MSG_INFO, "WPA: Invalid EAPOL-Key frame - " "key_data overflow (%d > %lu)", key_data_length, (unsigned long) (data_len - sizeof(*hdr) - sizeof(*key))); return; } /* FIX: verify that the EAPOL-Key frame was encrypted if pairwise keys * are set */ if ((key_info & (WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_REQUEST)) == (WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_REQUEST)) { if (key_info & WPA_KEY_INFO_ERROR) { msg = SMK_ERROR; msgtxt = "SMK Error"; } else { msg = SMK_M1; msgtxt = "SMK M1"; } } else if (key_info & WPA_KEY_INFO_SMK_MESSAGE) { msg = SMK_M3; msgtxt = "SMK M3"; } else if (key_info & WPA_KEY_INFO_REQUEST) { msg = REQUEST; msgtxt = "Request"; } else if (!(key_info & WPA_KEY_INFO_KEY_TYPE)) { msg = GROUP_2; msgtxt = "2/2 Group"; } else if (key_data_length == 0) { msg = PAIRWISE_4; msgtxt = "4/4 Pairwise"; } else { msg = PAIRWISE_2; msgtxt = "2/4 Pairwise"; } /* TODO: key_info type validation for PeerKey */ if (msg == REQUEST || msg == PAIRWISE_2 || msg == PAIRWISE_4 || msg == GROUP_2) { u16 ver = key_info & WPA_KEY_INFO_TYPE_MASK; if (sm->pairwise == WPA_CIPHER_CCMP) { if (wpa_use_aes_cmac(sm) && ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) { wpa_auth_logger(wpa_auth, sm->addr, LOGGER_WARNING, "advertised support for " "AES-128-CMAC, but did not " "use it"); return; } if (!wpa_use_aes_cmac(sm) && ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) { wpa_auth_logger(wpa_auth, sm->addr, LOGGER_WARNING, "did not use HMAC-SHA1-AES " "with CCMP"); return; } } } if (key_info & WPA_KEY_INFO_REQUEST) { if (sm->req_replay_counter_used && os_memcmp(key->replay_counter, sm->req_replay_counter, WPA_REPLAY_COUNTER_LEN) <= 0) { wpa_auth_logger(wpa_auth, sm->addr, LOGGER_WARNING, "received EAPOL-Key request with " "replayed counter"); return; } } if (!(key_info & WPA_KEY_INFO_REQUEST) && !wpa_replay_counter_valid(sm, key->replay_counter)) { int i; wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO, "received EAPOL-Key %s with unexpected " "replay counter", msgtxt); for (i = 0; i < RSNA_MAX_EAPOL_RETRIES; i++) { if (!sm->key_replay[i].valid) break; wpa_hexdump(MSG_DEBUG, "pending replay counter", sm->key_replay[i].counter, WPA_REPLAY_COUNTER_LEN); } wpa_hexdump(MSG_DEBUG, "received replay counter", key->replay_counter, WPA_REPLAY_COUNTER_LEN); return; } switch (msg) { case PAIRWISE_2: if (sm->wpa_ptk_state != WPA_PTK_PTKSTART && sm->wpa_ptk_state != WPA_PTK_PTKCALCNEGOTIATING) { wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO, "received EAPOL-Key msg 2/4 in " "invalid state (%d) - dropped", sm->wpa_ptk_state); return; } if (sm->wpa_ie == NULL || sm->wpa_ie_len != key_data_length || os_memcmp(sm->wpa_ie, key + 1, key_data_length) != 0) { wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, "WPA IE from (Re)AssocReq did not " "match with msg 2/4"); if (sm->wpa_ie) { wpa_hexdump(MSG_DEBUG, "WPA IE in AssocReq", sm->wpa_ie, sm->wpa_ie_len); } wpa_hexdump(MSG_DEBUG, "WPA IE in msg 2/4", (u8 *) (key + 1), key_data_length); /* MLME-DEAUTHENTICATE.request */ wpa_sta_disconnect(wpa_auth, sm->addr); return; } break; case PAIRWISE_4: if (sm->wpa_ptk_state != WPA_PTK_PTKINITNEGOTIATING || !sm->PTK_valid) { wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO, "received EAPOL-Key msg 4/4 in " "invalid state (%d) - dropped", sm->wpa_ptk_state); return; } break; case GROUP_2: if (sm->wpa_ptk_group_state != WPA_PTK_GROUP_REKEYNEGOTIATING || !sm->PTK_valid) { wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO, "received EAPOL-Key msg 2/2 in " "invalid state (%d) - dropped", sm->wpa_ptk_group_state); return; } break;#ifdef CONFIG_PEERKEY case SMK_M1: case SMK_M3: case SMK_ERROR: if (!wpa_auth->conf.peerkey) { wpa_printf(MSG_DEBUG, "RSN: SMK M1/M3/Error, but " "PeerKey use disabled - ignoring message"); return; } if (!sm->PTK_valid) { wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, "received EAPOL-Key msg SMK in " "invalid state - dropped"); return; } break;#else /* CONFIG_PEERKEY */ case SMK_M1: case SMK_M3: case SMK_ERROR: return; /* STSL disabled - ignore SMK messages */#endif /* CONFIG_PEERKEY */ case REQUEST: break; } wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG, "received EAPOL-Key frame (%s)", msgtxt); if (key_info & WPA_KEY_INFO_ACK) { wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, "received invalid EAPOL-Key: Key Ack set"); return; } if (!(key_info & WPA_KEY_INFO_MIC)) { wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, "received invalid EAPOL-Key: Key MIC not set"); return; } sm->MICVerified = FALSE; if (sm->PTK_valid) { if (wpa_verify_key_mic(&sm->PTK, data, data_len)) { wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, "received EAPOL-Key with invalid MIC"); return; } sm->MICVerified = TRUE; eloop_cancel_timeout(wpa_send_eapol_timeout, wpa_auth, sm); } if (key_info & WPA_KEY_INFO_REQUEST) { if (sm->MICVerified) { sm->req_replay_counter_used = 1; os_memcpy(sm->req_replay_counter, key->replay_counter, WPA_REPLAY_COUNTER_LEN); } else { wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, "received EAPOL-Key request with " "invalid MIC"); return; } /* * TODO: should decrypt key data field if encryption was used; * even though MAC address KDE is not normally encrypted, * supplicant is allowed to encrypt it. */ if (msg == SMK_ERROR) {#ifdef CONFIG_PEERKEY wpa_smk_error(wpa_auth, sm, key);#endif /* CONFIG_PEERKEY */ return; } else if (key_info & WPA_KEY_INFO_ERROR) { /* Supplicant reported a Michael MIC error */ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, "received EAPOL-Key Error Request " "(STA detected Michael MIC failure)"); wpa_auth_mic_failure_report(wpa_auth, sm->addr); sm->dot11RSNAStatsTKIPRemoteMICFailures++; wpa_auth->dot11RSNAStatsTKIPRemoteMICFailures++; /* Error report is not a request for a new key * handshake, but since Authenticator may do it, let's * change the keys now anyway. */ wpa_request_new_ptk(sm); } else if (key_info & WPA_KEY_INFO_KEY_TYPE) { wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, "received EAPOL-Key Request for new " "4-Way Handshake"); wpa_request_new_ptk(sm);#ifdef CONFIG_PEERKEY } else if (msg == SMK_M1) { wpa_smk_m1(wpa_auth, sm, key);#endif /* CONFIG_PEERKEY */ } else if (key_data_length > 0 && wpa_parse_kde_ies((const u8 *) (key + 1), key_data_length, &kde) == 0 && kde.mac_addr) { } else { wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, "received EAPOL-Key Request for GTK " "rekeying"); /* FIX: why was this triggering PTK rekeying for the * STA that requested Group Key rekeying?? */ /* wpa_request_new_ptk(sta->wpa_sm); */ eloop_cancel_timeout(wpa_rekey_gtk, wpa_auth, NULL); wpa_rekey_gtk(wpa_auth, NULL); } } else { /* Do not allow the same key replay counter to be reused. This * does also invalidate all other pending replay counters if * retransmissions were used, i.e., we will only process one of * the pending replies and ignore rest if more than one is * received. */ sm->key_replay[0].valid = FALSE; }#ifdef CONFIG_PEERKEY if (msg == SMK_M3) { wpa_smk_m3(wpa_auth, sm, key); return; }#endif /* CONFIG_PEERKEY */ os_free(sm->last_rx_eapol_key); sm->last_rx_eapol_key = os_malloc(data_len); if (sm->last_rx_eapol_key == NULL) return; os_memcpy(sm->last_rx_eapol_key, data, data_len); sm->last_rx_eapol_key_len = data_len; sm->EAPOLKeyReceived = TRUE; sm->EAPOLKeyPairwise = !!(key_info & WPA_KEY_INFO_KEY_TYPE); sm->EAPOLKeyRequest = !!(key_info & WPA_KEY_INFO_REQUEST); os_memcpy(sm->SNonce, key->key_nonce, WPA_NONCE_LEN); wpa_sm_step(sm);}static void wpa_gmk_to_gtk(const u8 *gmk, const u8 *addr, const u8 *gnonce, u8 *gtk, size_t gtk_len){ u8 data[ETH_ALEN + WPA_NONCE_LEN]; /* GTK = PRF-X(GMK, "Group key expansion", AA || GNonce) */ os_memcpy(data, addr, ETH_ALEN); os_memcpy(data + ETH_ALEN, gnonce, WPA_NONCE_LEN);#ifdef CONFIG_IEEE80211W sha256_prf(gmk, WPA_GMK_LEN, "Group key expansion", data, sizeof(data), gtk, gtk_len);#else /* CONFIG_IEEE80211W */ sha1_prf(gmk, WPA_GMK_LEN, "Group key expansion", data, sizeof(data), gtk, gtk_len);#endif /* CONFIG_IEEE80211W */ wpa_hexdump_key(MSG_DEBUG, "GMK", gmk, WPA_GMK_LEN); wpa_hexdump_key(MSG_DEBUG, "GTK", gtk, gtk_len);}static void wpa_send_eapol_timeout(void *eloop_ctx, void *timeout_ctx){ struct wpa_authenticator *wpa_auth = eloop_ctx; struct wpa_state_machine *sm = timeout_ctx; wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG, "EAPOL-Key timeout"); sm->TimeoutEvt = TRUE; wpa_sm_step(sm);}void __wpa_send_eapol(struct wpa_authenticator *wpa_auth, struct wpa_state_machine *sm, int key_info, const u8 *key_rsc, const u8 *nonce, const u8 *kde, size_t kde_len, int keyidx, int encr, int force_version){ struct ieee802_1x_hdr *hdr; struct wpa_eapol_key *key; size_t len; int alg; int key_data_len, pad_len = 0; u8 *buf, *pos; int version, pairwise; int i; len = sizeof(struct ieee802_1x_hdr) + sizeof(struct wpa_eapol_key); if (force_version) version = force_version; else if (wpa_use_aes_cmac(sm)) version = WPA_KEY_INFO_TYPE_AES_128_CMAC; else if (sm->pairwise == WPA_CIPHER_CCMP) version = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES; else version = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4; pairwise = key_info & WPA_KEY_INFO_KEY_TYPE; wpa_printf(MSG_DEBUG, "WPA: Send EAPOL(version=%d secure=%d mic=%d " "ack=%d install=%d pairwise=%d kde_len=%lu keyidx=%d " "encr=%d)", version, (key_info & WPA_KEY_INFO_SECURE) ? 1 : 0, (key_info & WPA_KEY_INFO_MIC) ? 1 : 0, (key_info & WPA_KEY_INFO_ACK) ? 1 : 0, (key_info & WPA_KEY_INFO_INSTALL) ? 1 : 0, pairwise, (unsigned long) kde_len, keyidx, encr); key_data_len = kde_len; if ((version == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES || version == WPA_KEY_INFO_TYPE_AES_128_CMAC) && encr) { 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 = os_zalloc(len); if (hdr == NULL) return; hdr->version = wpa_auth->conf.eapol_version; hdr->type = IEEE802_1X_TYPE_EAPOL_KEY;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -