📄 wpa.c
字号:
data->capabilities = WPA_GET_LE16(pos); pos += 2; left -= 2; } if (left >= 2) { data->num_pmkid = WPA_GET_LE16(pos); pos += 2; left -= 2; if (left < data->num_pmkid * PMKID_LEN) { wpa_printf(MSG_DEBUG, "%s: PMKID underflow " "(num_pmkid=%d left=%d)", __func__, data->num_pmkid, left); data->num_pmkid = 0; } else { data->pmkid = pos; pos += data->num_pmkid * PMKID_LEN; left -= data->num_pmkid * PMKID_LEN; } } if (left > 0) { wpa_printf(MSG_DEBUG, "%s: ie has %u trailing bytes - ignored", __func__, left); } return 0;}/** * wpa_parse_wpa_ie - Parse WPA/RSN IE * @wpa_ie: Pointer to WPA or RSN IE * @wpa_ie_len: Length of the WPA/RSN IE * @data: Pointer to data area for parsing results * Returns: 0 on success, -1 on failure * * Parse the contents of WPA or RSN IE and write the parsed data into data. */int wpa_parse_wpa_ie(const u8 *wpa_ie, size_t wpa_ie_len, struct wpa_ie_data *data){ if (wpa_ie_len >= 1 && wpa_ie[0] == RSN_INFO_ELEM) return wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, data); else return wpa_parse_wpa_ie_wpa(wpa_ie, wpa_ie_len, data);}static int wpa_gen_wpa_ie_wpa(u8 *wpa_ie, size_t wpa_ie_len, int pairwise_cipher, int group_cipher, int key_mgmt){ u8 *pos; struct wpa_ie_hdr *hdr; if (wpa_ie_len < sizeof(*hdr) + WPA_SELECTOR_LEN + 2 + WPA_SELECTOR_LEN + 2 + WPA_SELECTOR_LEN) return -1; hdr = (struct wpa_ie_hdr *) wpa_ie; hdr->elem_id = GENERIC_INFO_ELEM; memcpy(&hdr->oui, WPA_OUI_TYPE, WPA_SELECTOR_LEN); WPA_PUT_LE16(hdr->version, WPA_VERSION); pos = (u8 *) (hdr + 1); if (group_cipher == WPA_CIPHER_CCMP) { memcpy(pos, WPA_CIPHER_SUITE_CCMP, WPA_SELECTOR_LEN); } else if (group_cipher == WPA_CIPHER_TKIP) { memcpy(pos, WPA_CIPHER_SUITE_TKIP, WPA_SELECTOR_LEN); } else if (group_cipher == WPA_CIPHER_WEP104) { memcpy(pos, WPA_CIPHER_SUITE_WEP104, WPA_SELECTOR_LEN); } else if (group_cipher == WPA_CIPHER_WEP40) { memcpy(pos, WPA_CIPHER_SUITE_WEP40, WPA_SELECTOR_LEN); } else { wpa_printf(MSG_WARNING, "Invalid group cipher (%d).", group_cipher); return -1; } pos += WPA_SELECTOR_LEN; *pos++ = 1; *pos++ = 0; if (pairwise_cipher == WPA_CIPHER_CCMP) { memcpy(pos, WPA_CIPHER_SUITE_CCMP, WPA_SELECTOR_LEN); } else if (pairwise_cipher == WPA_CIPHER_TKIP) { memcpy(pos, WPA_CIPHER_SUITE_TKIP, WPA_SELECTOR_LEN); } else if (pairwise_cipher == WPA_CIPHER_NONE) { memcpy(pos, WPA_CIPHER_SUITE_NONE, WPA_SELECTOR_LEN); } else { wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).", pairwise_cipher); return -1; } pos += WPA_SELECTOR_LEN; *pos++ = 1; *pos++ = 0; if (key_mgmt == WPA_KEY_MGMT_IEEE8021X) { memcpy(pos, WPA_AUTH_KEY_MGMT_UNSPEC_802_1X, WPA_SELECTOR_LEN); } else if (key_mgmt == WPA_KEY_MGMT_PSK) { memcpy(pos, WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X, WPA_SELECTOR_LEN); } else if (key_mgmt == WPA_KEY_MGMT_WPA_NONE) { memcpy(pos, WPA_AUTH_KEY_MGMT_NONE, WPA_SELECTOR_LEN); } else { wpa_printf(MSG_WARNING, "Invalid key management type (%d).", key_mgmt); return -1; } pos += WPA_SELECTOR_LEN; /* WPA Capabilities; use defaults, so no need to include it */ hdr->len = (pos - wpa_ie) - 2; WPA_ASSERT(pos - wpa_ie <= wpa_ie_len); return pos - wpa_ie;}static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len, int pairwise_cipher, int group_cipher, int key_mgmt, struct wpa_sm *sm){ u8 *pos; struct rsn_ie_hdr *hdr; if (rsn_ie_len < sizeof(*hdr) + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN + 2 + (sm->cur_pmksa ? 2 + PMKID_LEN : 0)) return -1; hdr = (struct rsn_ie_hdr *) rsn_ie; hdr->elem_id = RSN_INFO_ELEM; WPA_PUT_LE16(hdr->version, RSN_VERSION); pos = (u8 *) (hdr + 1); if (group_cipher == WPA_CIPHER_CCMP) { memcpy(pos, RSN_CIPHER_SUITE_CCMP, RSN_SELECTOR_LEN); } else if (group_cipher == WPA_CIPHER_TKIP) { memcpy(pos, RSN_CIPHER_SUITE_TKIP, RSN_SELECTOR_LEN); } else if (group_cipher == WPA_CIPHER_WEP104) { memcpy(pos, RSN_CIPHER_SUITE_WEP104, RSN_SELECTOR_LEN); } else if (group_cipher == WPA_CIPHER_WEP40) { memcpy(pos, RSN_CIPHER_SUITE_WEP40, RSN_SELECTOR_LEN); } else { wpa_printf(MSG_WARNING, "Invalid group cipher (%d).", group_cipher); return -1; } pos += RSN_SELECTOR_LEN; *pos++ = 1; *pos++ = 0; if (pairwise_cipher == WPA_CIPHER_CCMP) { memcpy(pos, RSN_CIPHER_SUITE_CCMP, RSN_SELECTOR_LEN); } else if (pairwise_cipher == WPA_CIPHER_TKIP) { memcpy(pos, RSN_CIPHER_SUITE_TKIP, RSN_SELECTOR_LEN); } else if (pairwise_cipher == WPA_CIPHER_NONE) { memcpy(pos, RSN_CIPHER_SUITE_NONE, RSN_SELECTOR_LEN); } else { wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).", pairwise_cipher); return -1; } pos += RSN_SELECTOR_LEN; *pos++ = 1; *pos++ = 0; if (key_mgmt == WPA_KEY_MGMT_IEEE8021X) { memcpy(pos, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X, RSN_SELECTOR_LEN); } else if (key_mgmt == WPA_KEY_MGMT_PSK) { memcpy(pos, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X, RSN_SELECTOR_LEN); } else { wpa_printf(MSG_WARNING, "Invalid key management type (%d).", key_mgmt); return -1; } pos += RSN_SELECTOR_LEN; /* RSN Capabilities */ *pos++ = 0; *pos++ = 0; if (sm->cur_pmksa) { /* PMKID Count (2 octets, little endian) */ *pos++ = 1; *pos++ = 0; /* PMKID */ memcpy(pos, sm->cur_pmksa->pmkid, PMKID_LEN); pos += PMKID_LEN; } hdr->len = (pos - rsn_ie) - 2; WPA_ASSERT(pos - rsn_ie <= rsn_ie_len); return pos - rsn_ie;}/** * wpa_gen_wpa_ie - Generate WPA/RSN IE based on current security policy * @sm: Pointer to WPA state machine data from wpa_sm_init() * @wpa_ie: Pointer to memory area for the generated WPA/RSN IE * @wpa_ie_len: Maximum length of the generated WPA/RSN IE * Returns: Length of the generated WPA/RSN IE or -1 on failure */static int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len){ if (sm->proto == WPA_PROTO_RSN) return wpa_gen_wpa_ie_rsn(wpa_ie, wpa_ie_len, sm->pairwise_cipher, sm->group_cipher, sm->key_mgmt, sm); else return wpa_gen_wpa_ie_wpa(wpa_ie, wpa_ie_len, sm->pairwise_cipher, sm->group_cipher, sm->key_mgmt);}/** * wpa_pmk_to_ptk - Calculate PTK from PMK, addresses, and nonces * @pmk: Pairwise master key * @addr1: AA or SA * @addr2: SA or AA * @nonce1: ANonce or SNonce * @nonce2: SNonce or ANonce * @ptk: Buffer for pairwise transient key * @ptk_len: Length of PTK * * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy * PTK = PRF-X(PMK, "Pairwise key expansion", * Min(AA, SA) || Max(AA, SA) || * Min(ANonce, SNonce) || Max(ANonce, SNonce)) */static void wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const u8 *addr1, const u8 *addr2, const u8 *nonce1, const u8 *nonce2, u8 *ptk, size_t ptk_len){ u8 data[2 * ETH_ALEN + 2 * 32]; 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, 32) < 0) { memcpy(data + 2 * ETH_ALEN, nonce1, 32); memcpy(data + 2 * ETH_ALEN + 32, nonce2, 32); } else { memcpy(data + 2 * ETH_ALEN, nonce2, 32); memcpy(data + 2 * ETH_ALEN + 32, nonce1, 32); } sha1_prf(pmk, pmk_len, "Pairwise key expansion", data, sizeof(data), ptk, ptk_len); wpa_hexdump_key(MSG_DEBUG, "WPA: PMK", pmk, pmk_len); wpa_hexdump_key(MSG_DEBUG, "WPA: PTK", ptk, ptk_len);}/** * wpa_eapol_key_mic - Calculate EAPOL-Key MIC * @key: EAPOL-Key Key Confirmation Key (KCK) * @ver: Key descriptor version (WPA_KEY_INFO_TYPE_*) * @buf: Pointer to the beginning of the EAPOL header (version field) * @len: Length of the EAPOL frame (from EAPOL header to the end of the frame) * @mic: Pointer to the buffer to which the EAPOL-Key MIC is written * * Calculate EAPOL-Key MIC for an EAPOL-Key packet. The EAPOL-Key MIC field has * to be cleared (all zeroes) when calling this function. * * Note: 'IEEE Std 802.11i-2004 - 8.5.2 EAPOL-Key frames' has an error in the * description of the Key MIC calculation. It includes packet data from the * beginning of the EAPOL-Key header, not EAPOL header. This incorrect change * happened during final editing of the standard and the correct behavior is * defined in the last draft (IEEE 802.11i/D10). */static void wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len, u8 *mic){ if (ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4) { hmac_md5(key, 16, buf, len, mic); } else if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) { u8 hash[SHA1_MAC_LEN]; hmac_sha1(key, 16, buf, len, hash); memcpy(mic, hash, MD5_MAC_LEN); }}static void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck, int ver, const u8 *dest, u16 proto, u8 *msg, size_t msg_len, u8 *key_mic){ if (key_mic) { wpa_eapol_key_mic(kck, ver, msg, msg_len, key_mic); } wpa_hexdump(MSG_MSGDUMP, "WPA: TX EAPOL-Key", msg, msg_len); wpa_sm_ether_send(sm, dest, proto, msg, msg_len); eapol_sm_notify_tx_eapol_key(sm->eapol); free(msg);}/** * wpa_sm_key_request - Send EAPOL-Key Request * @sm: Pointer to WPA state machine data from wpa_sm_init() * @error: Indicate whether this is an Michael MIC error report * @pairwise: 1 = error report for pairwise packet, 0 = for group packet * Returns: Pointer to the current network structure or %NULL on failure * * Send an EAPOL-Key Request to the current authenticator. This function is * used to request rekeying and it is usually called when a local Michael MIC * failure is detected. */void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise){ size_t rlen; struct wpa_eapol_key *reply; int key_info, ver; u8 bssid[ETH_ALEN], *rbuf; if (sm->pairwise_cipher == WPA_CIPHER_CCMP) ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES; else ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4; if (wpa_sm_get_bssid(sm, bssid) < 0) { wpa_printf(MSG_WARNING, "Failed to read BSSID for EAPOL-Key " "request"); return; } rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL, sizeof(*reply), &rlen, (void *) &reply); if (rbuf == NULL) return; reply->type = sm->proto == WPA_PROTO_RSN ? EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA; key_info = WPA_KEY_INFO_REQUEST | ver; if (sm->ptk_set) key_info |= WPA_KEY_INFO_MIC; if (error) key_info |= WPA_KEY_INFO_ERROR; if (pairwise) key_info |= WPA_KEY_INFO_KEY_TYPE; WPA_PUT_BE16(reply->key_info, key_info); WPA_PUT_BE16(reply->key_length, 0); memcpy(reply->replay_counter, sm->request_counter, WPA_REPLAY_COUNTER_LEN); inc_byte_array(sm->request_counter, WPA_REPLAY_COUNTER_LEN); WPA_PUT_BE16(reply->key_data_length, 0); wpa_printf(MSG_INFO, "WPA: Sending EAPOL-Key Request (error=%d " "pairwise=%d ptk_set=%d len=%lu)", error, pairwise, sm->ptk_set, (unsigned long) rlen); wpa_eapol_key_send(sm, sm->ptk.kck, ver, bssid, ETH_P_EAPOL, rbuf, rlen, key_info & WPA_KEY_INFO_MIC ? reply->key_mic : NULL);}struct wpa_eapol_ie_parse { const u8 *wpa_ie; size_t wpa_ie_len; const u8 *rsn_ie; size_t rsn_ie_len; const u8 *pmkid; const u8 *gtk; size_t gtk_len;};/** * wpa_supplicant_parse_generic - Parse EAPOL-Key Key Data Generic IEs * @pos: Pointer to the IE header * @end: Pointer to the end of the Key Data buffer * @ie: Pointer to parsed IE data * Returns: 0 on success, 1 if end mark is found, -1 on failure */static int wpa_supplicant_parse_generic(const u8 *pos, const u8 *end, struct wpa_eapol_ie_parse *ie){ if (pos[1] == 0) return 1; if (pos[1] >= 6 && memcmp(pos + 2, WPA_OUI_TYPE, WPA_SELECTOR_LEN) == 0 && pos[2 + WPA_SELECTOR_LEN] == 1 && pos[2 + WPA_SELECTOR_LEN + 1] == 0) { ie->wpa_ie = pos; ie->wpa_ie_len = pos[1] + 2; return 0; } if (pos + 1 + RSN_SELECTOR_LEN < end && pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN && memcmp(pos + 2, RSN_KEY_DATA_PMKID, RSN_SELECTOR_LEN) == 0) { ie->pmkid = pos + 2 + RSN_SELECTOR_LEN; return 0; } if (pos[1] > RSN_SELECTOR_LEN + 2 && memcmp(pos + 2, RSN_KEY_DATA_GROUPKEY, RSN_SELECTOR_LEN) == 0) { ie->gtk = pos + 2 + RSN_SELECTOR_LEN; ie->gtk_len = pos[1] - RSN_SELECTOR_LEN; } return 0;}/** * wpa_supplicant_parse_ies - Parse EAPOL-Key Key Data IEs * @buf: Pointer to the Key Data buffer * @len: Key Data Length * @ie: Pointer to parsed IE data * Returns: 0 on success, -1 on failure */static int wpa_supplicant_parse_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie){ const u8 *pos, *end; int ret = 0; memset(ie, 0, sizeof(*ie)); for (pos = buf, end = pos + len; pos + 1 < end; pos += 2 + pos[1]) { if (pos + 2 + pos[1] > end) { wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key Key Data " "underflow (ie=%d len=%d)", pos[0], pos[1]); ret = -1; break; } if (*pos == RSN_INFO_ELEM) { ie->rsn_ie = pos; ie->rsn_ie_len = pos[1] + 2; } else if (*pos == GENERIC_INFO_ELEM) { ret = wpa_supplicant_parse_generic(pos, end, ie); if (ret < 0) break; if (ret > 0) { ret = 0; break; } } else { wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized EAPOL-Key "
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -