📄 wpa_ft.c
字号:
/* * WPA Supplicant - IEEE 802.11r - Fast BSS Transition * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */#include "includes.h"#include "common.h"#include "wpa.h"#include "wpa_i.h"#include "wpa_ie.h"#include "aes_wrap.h"#include "ieee802_11_defs.h"#ifdef CONFIG_IEEE80211Rint wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr, const struct wpa_eapol_key *key, struct wpa_ptk *ptk){ u8 pmk_r1_name[WPA_PMK_NAME_LEN]; u8 ptk_name[WPA_PMK_NAME_LEN]; const u8 *anonce = key->key_nonce; if (sm->xxkey_len == 0) { wpa_printf(MSG_DEBUG, "FT: XXKey not available for key " "derivation"); return -1; } wpa_derive_pmk_r0(sm->xxkey, sm->xxkey_len, sm->ssid, sm->ssid_len, sm->mobility_domain, sm->r0kh_id, sm->r0kh_id_len, sm->own_addr, sm->pmk_r0, sm->pmk_r0_name); wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", sm->pmk_r0, PMK_LEN); wpa_hexdump(MSG_DEBUG, "FT: PMKR0Name", sm->pmk_r0_name, WPA_PMK_NAME_LEN); wpa_derive_pmk_r1(sm->pmk_r0, sm->pmk_r0_name, sm->r1kh_id, sm->own_addr, sm->pmk_r1, pmk_r1_name); wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", sm->pmk_r1, PMK_LEN); wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", pmk_r1_name, WPA_PMK_NAME_LEN); wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->snonce, anonce, sm->own_addr, sm->bssid, pmk_r1_name, (u8 *) ptk, sizeof(*ptk), ptk_name); wpa_hexdump_key(MSG_DEBUG, "FT: PTK", (u8 *) ptk, sizeof(*ptk)); wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN); return 0;}/** * wpa_sm_set_ft_params - Set FT (IEEE 802.11r) parameters * @sm: Pointer to WPA state machine data from wpa_sm_init() * @mobility_domain: Mobility domain identifier (2 octets) * @r0kh_id: PMK-R0 key holder identity (1-48 octets) * @r0kh_id_len: R0KH-ID length (1-48) * @r1kh_id: PMK-R1 key holder identity (16 octets) * Returns: 0 on success, -1 on failure */int wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *mobility_domain, const u8 *r0kh_id, size_t r0kh_id_len, const u8 *r1kh_id){ if (sm && mobility_domain) { wpa_hexdump(MSG_DEBUG, "FT: Mobility domain", mobility_domain, MOBILITY_DOMAIN_ID_LEN); os_memcpy(sm->mobility_domain, mobility_domain, MOBILITY_DOMAIN_ID_LEN); } else if (sm) os_memset(sm->mobility_domain, 0, MOBILITY_DOMAIN_ID_LEN); if (sm && r0kh_id) { if (r0kh_id_len > FT_R0KH_ID_MAX_LEN) return -1; wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID", r0kh_id, r0kh_id_len); os_memcpy(sm->r0kh_id, r0kh_id, r0kh_id_len); sm->r0kh_id_len = r0kh_id_len; } else if (sm) { /* FIX: When should R0KH-ID be cleared? We need to keep the * old R0KH-ID in order to be able to use this during FT. */ /* * os_memset(sm->r0kh_id, 0, FT_R0KH_ID_LEN); * sm->r0kh_id_len = 0; */ } if (sm && r1kh_id) { wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID", r1kh_id, FT_R1KH_ID_LEN); os_memcpy(sm->r1kh_id, r1kh_id, FT_R1KH_ID_LEN); } else if (sm) os_memset(sm->r1kh_id, 0, FT_R1KH_ID_LEN); return 0;}/** * wpa_ft_gen_req_ies - Generate FT (IEEE 802.11r) IEs for Auth Request * @sm: Pointer to WPA state machine data from wpa_sm_init() * @len: Buffer for returning the length of the IEs * @anonce: ANonce or %NULL if not yet available * @pmk_name: PMKR0Name or PMKR1Name to be added into the RSN IE PMKID List * @kck: 128-bit KCK for MIC or %NULL if no MIC is used * @target_ap: Target AP address * Returns: Pointer to buffer with IEs or %NULL on failure * * Caller is responsible for freeing the returned buffer with os_free(); */static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len, const u8 *anonce, const u8 *pmk_name, const u8 *kck, const u8 *target_ap){ size_t buf_len; u8 *buf, *pos, *ftie_len, *ftie_pos; struct rsn_mdie *mdie; struct rsn_ftie *ftie; struct rsn_ie_hdr *rsnie; u16 capab; sm->ft_completed = 0; buf_len = 2 + sizeof(struct rsn_mdie) + 2 + sizeof(struct rsn_ftie) + 2 + sm->r0kh_id_len + 100; buf = os_zalloc(buf_len); if (buf == NULL) return NULL; pos = buf; /* RSNIE[PMKR0Name] */ rsnie = (struct rsn_ie_hdr *) pos; rsnie->elem_id = WLAN_EID_RSN; WPA_PUT_LE16(rsnie->version, RSN_VERSION); pos = (u8 *) (rsnie + 1); /* Group Suite Selector */ if (sm->group_cipher == WPA_CIPHER_CCMP) RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); else if (sm->group_cipher == WPA_CIPHER_TKIP) RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP); else { wpa_printf(MSG_WARNING, "FT: Invalid group cipher (%d)", sm->group_cipher); os_free(buf); return NULL; } pos += RSN_SELECTOR_LEN; /* Pairwise Suite Count */ WPA_PUT_LE16(pos, 1); pos += 2; /* Pairwise Suite List */ if (sm->pairwise_cipher == WPA_CIPHER_CCMP) RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); else if (sm->pairwise_cipher == WPA_CIPHER_TKIP) RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP); else { wpa_printf(MSG_WARNING, "FT: Invalid pairwise cipher (%d)", sm->pairwise_cipher); os_free(buf); return NULL; } pos += RSN_SELECTOR_LEN; /* Authenticated Key Management Suite Count */ WPA_PUT_LE16(pos, 1); pos += 2; /* Authenticated Key Management Suite List */ if (sm->key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X) RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X); else if (sm->key_mgmt == WPA_KEY_MGMT_FT_PSK) RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK); else { wpa_printf(MSG_WARNING, "FT: Invalid key management type (%d)", sm->key_mgmt); os_free(buf); return NULL; } pos += RSN_SELECTOR_LEN; /* RSN Capabilities */ capab = 0;#ifdef CONFIG_IEEE80211W if (sm->mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) capab |= WPA_CAPABILITY_MFPC;#endif /* CONFIG_IEEE80211W */ WPA_PUT_LE16(pos, capab); pos += 2; /* PMKID Count */ WPA_PUT_LE16(pos, 1); pos += 2; /* PMKID List [PMKR0Name/PMKR1Name] */ os_memcpy(pos, pmk_name, WPA_PMK_NAME_LEN); pos += WPA_PMK_NAME_LEN;#ifdef CONFIG_IEEE80211W if (sm->mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) { /* Management Group Cipher Suite */ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC); pos += RSN_SELECTOR_LEN; }#endif /* CONFIG_IEEE80211W */ rsnie->len = (pos - (u8 *) rsnie) - 2; /* MDIE */ *pos++ = WLAN_EID_MOBILITY_DOMAIN; *pos++ = sizeof(*mdie); mdie = (struct rsn_mdie *) pos; pos += sizeof(*mdie); os_memcpy(mdie->mobility_domain, sm->mobility_domain, MOBILITY_DOMAIN_ID_LEN); mdie->ft_capab = 0; /* FIX: copy from the target AP's MDIE */ /* FTIE[SNonce, R0KH-ID] */ ftie_pos = pos; *pos++ = WLAN_EID_FAST_BSS_TRANSITION; ftie_len = pos++; ftie = (struct rsn_ftie *) pos; pos += sizeof(*ftie); os_memcpy(ftie->snonce, sm->snonce, WPA_NONCE_LEN); if (anonce) os_memcpy(ftie->anonce, anonce, WPA_NONCE_LEN); /* R0KH-ID sub-element */ *pos++ = FTIE_SUBELEM_R0KH_ID; *pos++ = sm->r0kh_id_len; os_memcpy(pos, sm->r0kh_id, sm->r0kh_id_len); pos += sm->r0kh_id_len; *ftie_len = pos - ftie_len - 1; if (kck) { /* * IEEE Std 802.11r-2008, 11A.8.4 * MIC shall be calculated over: * non-AP STA MAC address * Target AP MAC address * Transaction seq number (5 for ReassocReq, 3 otherwise) * RSN IE * MDIE * FTIE (with MIC field set to 0) * RIC-Request (if present) */ ftie->mic_control[1] = 3; /* Information element count */ if (wpa_ft_mic(kck, sm->own_addr, target_ap, 5, ((u8 *) mdie) - 2, 2 + sizeof(*mdie), ftie_pos, 2 + *ftie_len, (u8 *) rsnie, 2 + rsnie->len, NULL, 0, ftie->mic) < 0) { wpa_printf(MSG_INFO, "FT: Failed to calculate MIC"); os_free(buf); return NULL; } } *len = pos - buf; return buf;}struct wpa_ft_ies { const u8 *mdie; size_t mdie_len; const u8 *ftie; size_t ftie_len; const u8 *r1kh_id; const u8 *gtk; size_t gtk_len; const u8 *r0kh_id; size_t r0kh_id_len; const u8 *rsn; size_t rsn_len; const u8 *rsn_pmkid; const u8 *tie; size_t tie_len; const u8 *igtk; size_t igtk_len;};static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len, struct wpa_ft_ies *parse){ const u8 *end, *pos; parse->ftie = ie; parse->ftie_len = ie_len; pos = ie + sizeof(struct rsn_ftie); end = ie + ie_len; while (pos + 2 <= end && pos + 2 + pos[1] <= end) { switch (pos[0]) { case FTIE_SUBELEM_R1KH_ID: if (pos[1] != FT_R1KH_ID_LEN) { wpa_printf(MSG_DEBUG, "FT: Invalid R1KH-ID " "length in FTIE: %d", pos[1]); return -1; } parse->r1kh_id = pos + 2; break; case FTIE_SUBELEM_GTK: parse->gtk = pos + 2; parse->gtk_len = pos[1]; break; case FTIE_SUBELEM_R0KH_ID: if (pos[1] < 1 || pos[1] > FT_R0KH_ID_MAX_LEN) { wpa_printf(MSG_DEBUG, "FT: Invalid R0KH-ID " "length in FTIE: %d", pos[1]); return -1; } parse->r0kh_id = pos + 2; parse->r0kh_id_len = pos[1]; break;#ifdef CONFIG_IEEE80211W case FTIE_SUBELEM_IGTK: parse->igtk = pos + 2; parse->igtk_len = pos[1]; break;#endif /* CONFIG_IEEE80211W */ } pos += 2 + pos[1]; } return 0;}static int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, struct wpa_ft_ies *parse){ const u8 *end, *pos; struct wpa_ie_data data; int ret; os_memset(parse, 0, sizeof(*parse)); if (ies == NULL) return 0; pos = ies; end = ies + ies_len; while (pos + 2 <= end && pos + 2 + pos[1] <= end) { switch (pos[0]) { case WLAN_EID_RSN: parse->rsn = pos + 2; parse->rsn_len = pos[1]; ret = wpa_parse_wpa_ie_rsn(parse->rsn - 2, parse->rsn_len + 2, &data); if (ret < 0) { wpa_printf(MSG_DEBUG, "FT: Failed to parse " "RSN IE: %d", ret); return -1; } if (data.num_pmkid == 1 && data.pmkid) parse->rsn_pmkid = data.pmkid; break; case WLAN_EID_MOBILITY_DOMAIN: parse->mdie = pos + 2; parse->mdie_len = pos[1]; break; case WLAN_EID_FAST_BSS_TRANSITION: if (wpa_ft_parse_ftie(pos + 2, pos[1], parse) < 0) return -1; break; case WLAN_EID_TIMEOUT_INTERVAL: parse->tie = pos + 2; parse->tie_len = pos[1]; break; } pos += 2 + pos[1]; } return 0;}static int wpa_ft_install_ptk(struct wpa_sm *sm, const u8 *bssid){ int keylen; wpa_alg alg; u8 null_rsc[6] = { 0, 0, 0, 0, 0, 0 }; wpa_printf(MSG_DEBUG, "FT: Installing PTK to the driver."); switch (sm->pairwise_cipher) { case WPA_CIPHER_CCMP: alg = WPA_ALG_CCMP; keylen = 16; break; case WPA_CIPHER_TKIP: alg = WPA_ALG_TKIP; keylen = 32; break; default: wpa_printf(MSG_WARNING, "FT: Unsupported pairwise cipher %d", sm->pairwise_cipher); return -1; } if (wpa_sm_set_key(sm, alg, bssid, 0, 1, null_rsc, sizeof(null_rsc), (u8 *) sm->ptk.tk1, keylen) < 0) { wpa_printf(MSG_WARNING, "FT: Failed to set PTK to the driver"); return -1; } return 0;}/** * wpa_ft_prepare_auth_request - Generate over-the-air auth request * @sm: Pointer to WPA state machine data from wpa_sm_init() * Returns: 0 on success, -1 on failure */int wpa_ft_prepare_auth_request(struct wpa_sm *sm){ u8 *ft_ies; size_t ft_ies_len; /* Generate a new SNonce */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -