📄 wpa.c
字号:
} neg->num_retries++; if (neg->num_retries > dot11RSNAConfigPairwiseUpdateCount) { wpa_printf(MSG_DEBUG, "RSN: STAKey handshake with " MACSTR " timed out", MAC2STR(dst)); wpa_stakey_remove(wpa_auth, neg); return; } wpa_printf(MSG_DEBUG, "RSN: Sending STAKey 1/2 to " MACSTR " (try=%d)", MAC2STR(dst), neg->num_retries); memset(&kde, 0, sizeof(kde)); kde.id = GENERIC_INFO_ELEM; kde.len = sizeof(kde) - 2 - 32 + neg->key_len; memcpy(kde.oui, RSN_KEY_DATA_STAKEY, RSN_SELECTOR_LEN); memcpy(kde.mac_addr, peer, ETH_ALEN); memcpy(kde.stakey, neg->key, neg->key_len); if (neg->alg == WPA_CIPHER_CCMP) version = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES; else version = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4; __wpa_send_eapol(wpa_auth, search.sm, 1, 1, 1, 0, 0, NULL, NULL /* nonce */, (u8 *) &kde, sizeof(kde) - 32 + neg->key_len, NULL, 0, 0, 1, version); eloop_register_timeout(dot11RSNAConfigPairwiseUpdateTimeOut / 1000, (dot11RSNAConfigPairwiseUpdateTimeOut % 1000) * 1000, wpa_stakey_step, wpa_auth, neg);}#endif /* CONFIG_STAKEY */static int wpa_stakey_remove(struct wpa_authenticator *wpa_auth, struct wpa_stakey_negotiation *neg){#ifdef CONFIG_STAKEY struct wpa_stakey_negotiation *pos, *prev; if (wpa_auth == NULL) return -1; pos = wpa_auth->stakey_negotiations; prev = NULL; while (pos) { if (pos == neg) { if (prev) prev->next = pos->next; else wpa_auth->stakey_negotiations = pos->next; eloop_cancel_timeout(wpa_stakey_step, wpa_auth, pos); free(pos); return 0; } prev = pos; pos = pos->next; }#endif /* CONFIG_STAKEY */ return -1;}#ifdef CONFIG_STAKEYstatic int wpa_stakey_initiate(struct wpa_authenticator *wpa_auth, const u8 *initiator, const u8 *peer, int alg){ struct wpa_stakey_negotiation *neg; if (wpa_auth == NULL) return -1; neg = wpa_stakey_get(wpa_auth, initiator, peer); if (neg) { wpa_printf(MSG_DEBUG, "RSN: Pending STAKey handshake in " "progress - ignoring new request"); return -1; } neg = wpa_zalloc(sizeof(*neg)); if (neg == NULL) return -1; memcpy(neg->initiator, initiator, ETH_ALEN); memcpy(neg->peer, peer, ETH_ALEN); neg->state = PEER; neg->alg = alg; if (alg == WPA_CIPHER_TKIP) neg->key_len = 32; else neg->key_len = 16; if (hostapd_get_rand(neg->key, neg->key_len)) { wpa_printf(MSG_DEBUG, "RSN: Failed to get random data for " "STAKey"); free(neg); return -1; } neg->next = wpa_auth->stakey_negotiations; wpa_auth->stakey_negotiations = neg; wpa_stakey_step(wpa_auth, neg); return 0;}#endif /* CONFIG_STAKEY */static void wpa_stakey_receive(struct wpa_authenticator *wpa_auth, const u8 *src_addr, const u8 *peer){#ifdef CONFIG_STAKEY struct wpa_stakey_negotiation *neg; neg = wpa_stakey_get(wpa_auth, src_addr, peer); if (neg == NULL) { wpa_printf(MSG_DEBUG, "RSN: No matching STAKey negotiation " "found - ignored received STAKey frame"); return; } if (neg->state == PEER && memcmp(src_addr, neg->peer, ETH_ALEN) == 0) { neg->state = INITIATOR; neg->num_retries = 0; wpa_printf(MSG_DEBUG, "RSN: STAKey completed with peer " MACSTR, MAC2STR(neg->peer)); eloop_cancel_timeout(wpa_stakey_step, wpa_auth, neg); wpa_stakey_step(wpa_auth, neg); } else if (neg->state == INITIATOR && memcmp(src_addr, neg->initiator, ETH_ALEN) == 0) { wpa_printf(MSG_DEBUG, "RSN: STAKey negotiation completed " MACSTR " <-> " MACSTR, MAC2STR(neg->initiator), MAC2STR(neg->peer)); wpa_stakey_remove(wpa_auth, neg); } else { wpa_printf(MSG_DEBUG, "RSN: Unexpected STAKey message - " "src " MACSTR " peer " MACSTR " - dropped", MAC2STR(src_addr), MAC2STR(peer)); }#endif /* CONFIG_STAKEY */}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, STAKEY_2, REQUEST } msg; char *msgtxt; struct wpa_eapol_ie_parse kde; const u8 *mac_addr = NULL; 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 = ntohs(key->key_info); key_data_length = ntohs(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_REQUEST) { msg = REQUEST; msgtxt = "Request"; } else if (!(key_info & WPA_KEY_INFO_KEY_TYPE)) { /* FIX: should decrypt key_data if encrypted */ if (key_data_length > 0 && wpa_parse_kde_ies((const u8 *) (key + 1), key_data_length, &kde) == 0 && kde.mac_addr) { msg = STAKEY_2; msgtxt = "2/2 STAKey"; mac_addr = kde.mac_addr; } else { 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"; } if (key_info & WPA_KEY_INFO_REQUEST) { if (sm->req_replay_counter_used && 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) && (!sm->key_replay_counter_valid || memcmp(key->replay_counter, sm->key_replay_counter, WPA_REPLAY_COUNTER_LEN) != 0)) { wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO, "received EAPOL-Key %s with unexpected " "replay counter", msgtxt); wpa_hexdump(MSG_DEBUG, "expected replay counter", sm->key_replay_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 || 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; case STAKEY_2: if (!sm->PTK_valid) { wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, "received EAPOL-Key msg STAKey 2/2 in " "invalid state - dropped"); return; } break; 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; 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 (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); } else if (key_data_length > 0 && wpa_parse_kde_ies((const u8 *) (key + 1), key_data_length, &kde) == 0 && kde.mac_addr) {#ifdef CONFIG_STAKEY /* STAKey Request */ if (!wpa_auth->conf.stakey) { wpa_printf(MSG_DEBUG, "RSN: STAKey Request, " "but STAKey use disabled - ignoring" " request"); } else if (kde.mac_addr_len != ETH_ALEN) { wpa_printf(MSG_DEBUG, "RSN: Invalid MAC " "address KDE length %d", kde.mac_addr_len); } else { int alg; wpa_printf(MSG_DEBUG, "RSN: STAKey Request for" " peer " MACSTR, MAC2STR(kde.mac_addr)); switch (key_info & WPA_KEY_INFO_TYPE_MASK) { case 1: alg = WPA_CIPHER_TKIP; break; case 2: alg = WPA_CIPHER_CCMP; break; default: wpa_printf(MSG_DEBUG, "Unexpected " "STAKey key version (%d)", key_info & WPA_KEY_INFO_TYPE_MASK); alg = WPA_CIPHER_NONE; break; } if (alg != WPA_CIPHER_NONE) { wpa_stakey_initiate(wpa_auth, sm->addr, kde.mac_addr, alg); } }#endif /* CONFIG_STAKEY */ } 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. */ sm->key_replay_counter_valid = FALSE; } if (msg == STAKEY_2) { wpa_stakey_receive(wpa_auth, sm->addr, mac_addr); return; } free(sm->last_rx_eapol_key); sm->last_rx_eapol_key = malloc(data_len); if (sm->last_rx_eapol_key == NULL) return; 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); memcpy(sm->SNonce, key->key_nonce, WPA_NONCE_LEN); wpa_sm_step(sm);}static void wpa_pmk_to_ptk(const u8 *pmk, const u8 *addr1, const u8 *addr2, const u8 *nonce1, const u8 *nonce2, u8 *ptk, size_t ptk_len){ u8 data[2 * ETH_ALEN + 2 * WPA_NONCE_LEN]; /* PTK = PRF-X(PMK, "Pairwise key expansion", * Min(AA, SA) || Max(AA, SA) || * Min(ANonce, SNonce) || Max(ANonce, SNonce)) */ if (memcmp(addr1, addr2, ETH_ALEN) < 0) { memcpy(data, addr1, ETH_ALEN); memcpy(data + ETH_ALEN, addr2, ETH_ALEN); } else { memcpy(data, addr2, ETH_ALEN); memcpy(data + ETH_ALEN, addr1, ETH_ALEN); } if (memcmp(nonce1, nonce2, WPA_NONCE_LEN) < 0) { memcpy(data + 2 * ETH_ALEN, nonce1, WPA_NONCE_LEN); memcpy(data + 2 * ETH_ALEN + WPA_NONCE_LEN, nonce2, WPA_NONCE_LEN); } else { memcpy(data + 2 * ETH_ALEN, nonce2, WPA_NONCE_LEN); memcpy(data + 2 * ETH_ALEN + WPA_NONCE_LEN, nonce1, WPA_NONCE_LEN); } sha1_prf(pmk, WPA_PMK_LEN, "Pairwise key expansion", data, sizeof(data), ptk, ptk_len); wpa_hexdump_key(MSG_DEBUG, "PMK", pmk, WPA_PMK_LEN); wpa_hexdump_key(MSG_DEBUG, "PTK", ptk, ptk_len);}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) */ memcpy(data, addr, ETH_ALEN); memcpy(data + ETH_ALEN, gnonce, WPA_NONCE_LEN); sha1_prf(gmk, WPA_GMK_LEN, "Group key expansion", data, sizeof(data), gtk, gtk_len); 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);}static int wpa_calc_eapol_key_mic(int ver, u8 *key, u8 *data, size_t len, u8 *mic){ u8 hash[SHA1_MAC_LEN]; switch (ver) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -