aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJouni Malinen <jouni@codeaurora.org>2019-08-22 19:14:47 (GMT)
committerJouni Malinen <j@w1.fi>2019-08-22 19:14:47 (GMT)
commitc38c62ff78a69168a5e8d6c40b23c9cb0fcbd8d1 (patch)
treeb623d192ae413664937a3c6a03c6cb7aef893c46
parentdbddbf1647e844f729a7705d458101e269e2c4a9 (diff)
downloadhostap-c38c62ff78a69168a5e8d6c40b23c9cb0fcbd8d1.zip
hostap-c38c62ff78a69168a5e8d6c40b23c9cb0fcbd8d1.tar.gz
hostap-c38c62ff78a69168a5e8d6c40b23c9cb0fcbd8d1.tar.bz2
wlantest: Derive PMK-R1 and PTK for FT protocol cases
Track PMK-R0/PMK-R0-Name from the initial mobility domain association and derive PMK-R1/PTK when the station uses FT protocol. This allows frames from additional roaming cases to be decrypted. Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
-rw-r--r--src/common/wpa_common.c4
-rw-r--r--src/common/wpa_common.h2
-rw-r--r--wlantest/rx_eapol.c22
-rw-r--r--wlantest/rx_mgmt.c220
-rw-r--r--wlantest/wlantest.h2
5 files changed, 240 insertions, 10 deletions
diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c
index a756958..de1e2cf 100644
--- a/src/common/wpa_common.c
+++ b/src/common/wpa_common.c
@@ -990,9 +990,11 @@ int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
wpa_hexdump(MSG_DEBUG, "FT: FTE-MIC",
ftie_sha384->mic,
sizeof(ftie_sha384->mic));
+ parse->fte_anonce = ftie_sha384->anonce;
wpa_hexdump(MSG_DEBUG, "FT: FTE-ANonce",
ftie_sha384->anonce,
WPA_NONCE_LEN);
+ parse->fte_snonce = ftie_sha384->snonce;
wpa_hexdump(MSG_DEBUG, "FT: FTE-SNonce",
ftie_sha384->snonce,
WPA_NONCE_LEN);
@@ -1009,8 +1011,10 @@ int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
ftie->mic_control, 2);
wpa_hexdump(MSG_DEBUG, "FT: FTE-MIC",
ftie->mic, sizeof(ftie->mic));
+ parse->fte_anonce = ftie->anonce;
wpa_hexdump(MSG_DEBUG, "FT: FTE-ANonce",
ftie->anonce, WPA_NONCE_LEN);
+ parse->fte_snonce = ftie->snonce;
wpa_hexdump(MSG_DEBUG, "FT: FTE-SNonce",
ftie->snonce, WPA_NONCE_LEN);
prot_ie_count = ftie->mic_control[1];
diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h
index cb511ff..7170267 100644
--- a/src/common/wpa_common.h
+++ b/src/common/wpa_common.h
@@ -451,6 +451,8 @@ struct wpa_ft_ies {
size_t gtk_len;
const u8 *r0kh_id;
size_t r0kh_id_len;
+ const u8 *fte_anonce;
+ const u8 *fte_snonce;
const u8 *rsn;
size_t rsn_len;
u16 rsn_capab;
diff --git a/wlantest/rx_eapol.c b/wlantest/rx_eapol.c
index 1af48ec..e184495 100644
--- a/wlantest/rx_eapol.c
+++ b/wlantest/rx_eapol.c
@@ -100,21 +100,23 @@ static int try_pmk(struct wlantest *wt, struct wlantest_bss *bss,
struct wpa_ptk ptk;
if (wpa_key_mgmt_ft(sta->key_mgmt)) {
- u8 pmk_r0[PMK_LEN];
- u8 pmk_r0_name[WPA_PMK_NAME_LEN];
u8 pmk_r1[PMK_LEN];
u8 pmk_r1_name[WPA_PMK_NAME_LEN];
u8 ptk_name[WPA_PMK_NAME_LEN];
- wpa_derive_pmk_r0(pmk->pmk, PMK_LEN,
- bss->ssid, bss->ssid_len, bss->mdid,
- bss->r0kh_id, bss->r0kh_id_len,
- sta->addr, pmk_r0, pmk_r0_name, 0);
- wpa_hexdump(MSG_DEBUG, "FT: PMK-R0", pmk_r0, PMK_LEN);
- wpa_hexdump(MSG_DEBUG, "FT: PMKR0Name", pmk_r0_name,
+ if (wpa_derive_pmk_r0(pmk->pmk, PMK_LEN,
+ bss->ssid, bss->ssid_len, bss->mdid,
+ bss->r0kh_id, bss->r0kh_id_len,
+ sta->addr, sta->pmk_r0, sta->pmk_r0_name,
+ 0) < 0)
+ return -1;
+ wpa_hexdump(MSG_DEBUG, "FT: PMK-R0", sta->pmk_r0, PMK_LEN);
+ wpa_hexdump(MSG_DEBUG, "FT: PMKR0Name", sta->pmk_r0_name,
WPA_PMK_NAME_LEN);
- wpa_derive_pmk_r1(pmk_r0, PMK_LEN, pmk_r0_name, bss->r1kh_id,
- sta->addr, pmk_r1, pmk_r1_name);
+ if (wpa_derive_pmk_r1(sta->pmk_r0, PMK_LEN, sta->pmk_r0_name,
+ bss->r1kh_id, sta->addr,
+ pmk_r1, pmk_r1_name) < 0)
+ return -1;
wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", pmk_r1, PMK_LEN);
wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", pmk_r1_name,
WPA_PMK_NAME_LEN);
diff --git a/wlantest/rx_mgmt.c b/wlantest/rx_mgmt.c
index c008138..39b23b2 100644
--- a/wlantest/rx_mgmt.c
+++ b/wlantest/rx_mgmt.c
@@ -162,6 +162,81 @@ static void process_fils_auth(struct wlantest *wt, struct wlantest_bss *bss,
}
+static void process_ft_auth(struct wlantest *wt, struct wlantest_bss *bss,
+ struct wlantest_sta *sta,
+ const struct ieee80211_mgmt *mgmt, size_t len)
+{
+ u16 trans;
+ struct wpa_ft_ies parse;
+ u8 pmk_r1[PMK_LEN];
+ u8 pmk_r1_name[WPA_PMK_NAME_LEN];
+ struct wpa_ptk ptk;
+ u8 ptk_name[WPA_PMK_NAME_LEN];
+ struct wlantest_bss *old_bss;
+ struct wlantest_sta *old_sta = NULL;
+
+ if (sta->auth_alg != WLAN_AUTH_FT ||
+ len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth))
+ return;
+
+ trans = le_to_host16(mgmt->u.auth.auth_transaction);
+
+ if (wpa_ft_parse_ies(mgmt->u.auth.variable,
+ len - IEEE80211_HDRLEN - sizeof(mgmt->u.auth),
+ &parse, -1)) {
+ add_note(wt, MSG_INFO,
+ "Could not parse FT Authentication Response frame");
+ return;
+ }
+
+ if (trans == 1) {
+ sta->key_mgmt = parse.key_mgmt;
+ sta->pairwise_cipher = parse.pairwise_cipher;
+ return;
+ }
+
+ if (trans != 2)
+ return;
+
+ /* TODO: Should find the latest updated PMK-R0 value here instead
+ * copying the one from the first found matching old STA entry. */
+ dl_list_for_each(old_bss, &wt->bss, struct wlantest_bss, list) {
+ if (old_bss == bss)
+ continue;
+ old_sta = sta_find(old_bss, sta->addr);
+ if (old_sta)
+ break;
+ }
+ if (!old_sta)
+ return;
+
+ os_memcpy(sta->pmk_r0, old_sta->pmk_r0, sizeof(sta->pmk_r0));
+ os_memcpy(sta->pmk_r0_name, old_sta->pmk_r0_name,
+ sizeof(sta->pmk_r0_name));
+
+ if (parse.r1kh_id)
+ os_memcpy(bss->r1kh_id, parse.r1kh_id, FT_R1KH_ID_LEN);
+
+ if (wpa_derive_pmk_r1(sta->pmk_r0, PMK_LEN, sta->pmk_r0_name,
+ bss->r1kh_id, sta->addr, pmk_r1, pmk_r1_name) < 0)
+ return;
+ wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", pmk_r1_name, WPA_PMK_NAME_LEN);
+
+ if (!parse.fte_anonce || !parse.fte_snonce ||
+ wpa_pmk_r1_to_ptk(pmk_r1, PMK_LEN, parse.fte_snonce,
+ parse.fte_anonce, sta->addr, bss->bssid,
+ pmk_r1_name, &ptk, ptk_name, sta->key_mgmt,
+ sta->pairwise_cipher) < 0)
+ return;
+
+ add_note(wt, MSG_DEBUG, "Derived new PTK");
+ os_memcpy(&sta->ptk, &ptk, sizeof(ptk));
+ sta->ptk_set = 1;
+ os_memset(sta->rsc_tods, 0, sizeof(sta->rsc_tods));
+ os_memset(sta->rsc_fromds, 0, sizeof(sta->rsc_fromds));
+}
+
+
static void rx_mgmt_auth(struct wlantest *wt, const u8 *data, size_t len)
{
const struct ieee80211_mgmt *mgmt;
@@ -210,6 +285,7 @@ static void rx_mgmt_auth(struct wlantest *wt, const u8 *data, size_t len)
sta->counters[WLANTEST_STA_COUNTER_AUTH_TX]++;
process_fils_auth(wt, bss, sta, mgmt, len);
+ process_ft_auth(wt, bss, sta, mgmt, len);
}
@@ -736,6 +812,8 @@ static void rx_mgmt_reassoc_req(struct wlantest *wt, const u8 *data,
sta->assocreq_ies_len);
sta_update_assoc(sta, &elems);
+
+ /* TODO: FT protocol: verify FTE MIC and update GTK/IGTK for the BSS */
}
@@ -928,6 +1006,145 @@ static void rx_mgmt_disassoc(struct wlantest *wt, const u8 *data, size_t len,
}
+static void rx_mgmt_action_ft_request(struct wlantest *wt,
+ const struct ieee80211_mgmt *mgmt,
+ size_t len)
+{
+ const u8 *ies;
+ size_t ies_len;
+ struct wpa_ft_ies parse;
+ struct wlantest_bss *bss;
+ struct wlantest_sta *sta;
+
+ if (len < 24 + 2 + 2 * ETH_ALEN) {
+ add_note(wt, MSG_INFO, "Too short FT Request frame");
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "FT Request: STA Address: " MACSTR
+ " Target AP Address: " MACSTR,
+ MAC2STR(mgmt->u.action.u.ft_action_req.sta_addr),
+ MAC2STR(mgmt->u.action.u.ft_action_req.target_ap_addr));
+ ies = mgmt->u.action.u.ft_action_req.variable;
+ ies_len = len - (24 + 2 + 2 * ETH_ALEN);
+ wpa_hexdump(MSG_DEBUG, "FT Request frame body", ies, ies_len);
+
+ if (wpa_ft_parse_ies(ies, ies_len, &parse, -1)) {
+ add_note(wt, MSG_INFO, "Could not parse FT Request frame body");
+ return;
+ }
+
+ bss = bss_get(wt, mgmt->u.action.u.ft_action_resp.target_ap_addr);
+ if (!bss) {
+ add_note(wt, MSG_INFO, "No BSS entry for Target AP");
+ return;
+ }
+
+ sta = sta_get(bss, mgmt->sa);
+ if (!sta)
+ return;
+
+ sta->key_mgmt = parse.key_mgmt;
+ sta->pairwise_cipher = parse.pairwise_cipher;
+}
+
+
+static void rx_mgmt_action_ft_response(struct wlantest *wt,
+ struct wlantest_sta *sta,
+ const struct ieee80211_mgmt *mgmt,
+ size_t len)
+{
+ struct wlantest_bss *bss;
+ struct wlantest_sta *new_sta;
+ const u8 *ies;
+ size_t ies_len;
+ struct wpa_ft_ies parse;
+ u8 pmk_r1[PMK_LEN];
+ u8 pmk_r1_name[WPA_PMK_NAME_LEN];
+ struct wpa_ptk ptk;
+ u8 ptk_name[WPA_PMK_NAME_LEN];
+
+ if (len < 24 + 2 + 2 * ETH_ALEN + 2) {
+ add_note(wt, MSG_INFO, "Too short FT Response frame from "
+ MACSTR, MAC2STR(mgmt->sa));
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "FT Response: STA Address: " MACSTR
+ " Target AP Address: " MACSTR " Status Code: %u",
+ MAC2STR(mgmt->u.action.u.ft_action_resp.sta_addr),
+ MAC2STR(mgmt->u.action.u.ft_action_resp.target_ap_addr),
+ le_to_host16(mgmt->u.action.u.ft_action_resp.status_code));
+ ies = mgmt->u.action.u.ft_action_req.variable;
+ ies_len = len - (24 + 2 + 2 * ETH_ALEN);
+ wpa_hexdump(MSG_DEBUG, "FT Response frame body", ies, ies_len);
+
+ if (wpa_ft_parse_ies(ies, ies_len, &parse, -1)) {
+ add_note(wt, MSG_INFO,
+ "Could not parse FT Response frame body");
+ return;
+ }
+
+ bss = bss_get(wt, mgmt->u.action.u.ft_action_resp.target_ap_addr);
+ if (!bss) {
+ add_note(wt, MSG_INFO, "No BSS entry for Target AP");
+ return;
+ }
+
+ if (parse.r1kh_id)
+ os_memcpy(bss->r1kh_id, parse.r1kh_id, FT_R1KH_ID_LEN);
+
+ if (wpa_derive_pmk_r1(sta->pmk_r0, PMK_LEN, sta->pmk_r0_name,
+ bss->r1kh_id, sta->addr, pmk_r1, pmk_r1_name) < 0)
+ return;
+ wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", pmk_r1_name, WPA_PMK_NAME_LEN);
+
+ new_sta = sta_get(bss, sta->addr);
+ if (!new_sta)
+ return;
+ os_memcpy(new_sta->pmk_r0, sta->pmk_r0, sizeof(sta->pmk_r0));
+ os_memcpy(new_sta->pmk_r0_name, sta->pmk_r0_name,
+ sizeof(sta->pmk_r0_name));
+ if (!parse.fte_anonce || !parse.fte_snonce ||
+ wpa_pmk_r1_to_ptk(pmk_r1, PMK_LEN, parse.fte_snonce,
+ parse.fte_anonce, new_sta->addr, bss->bssid,
+ pmk_r1_name, &ptk, ptk_name, new_sta->key_mgmt,
+ new_sta->pairwise_cipher) < 0)
+ return;
+
+ add_note(wt, MSG_DEBUG, "Derived new PTK");
+ os_memcpy(&new_sta->ptk, &ptk, sizeof(ptk));
+ new_sta->ptk_set = 1;
+ os_memset(new_sta->rsc_tods, 0, sizeof(new_sta->rsc_tods));
+ os_memset(new_sta->rsc_fromds, 0, sizeof(new_sta->rsc_fromds));
+}
+
+
+static void rx_mgmt_action_ft(struct wlantest *wt, struct wlantest_sta *sta,
+ const struct ieee80211_mgmt *mgmt,
+ size_t len, int valid)
+{
+ if (len < 24 + 2) {
+ add_note(wt, MSG_INFO, "Too short FT Action frame from " MACSTR,
+ MAC2STR(mgmt->sa));
+ return;
+ }
+
+ switch (mgmt->u.action.u.ft_action_req.action) {
+ case 1:
+ rx_mgmt_action_ft_request(wt, mgmt, len);
+ break;
+ case 2:
+ rx_mgmt_action_ft_response(wt, sta, mgmt, len);
+ break;
+ default:
+ add_note(wt, MSG_INFO, "Unsupported FT action value %u from "
+ MACSTR, mgmt->u.action.u.ft_action_req.action,
+ MAC2STR(mgmt->sa));
+ }
+}
+
+
static void rx_mgmt_action_sa_query_req(struct wlantest *wt,
struct wlantest_sta *sta,
const struct ieee80211_mgmt *mgmt,
@@ -1070,6 +1287,9 @@ static void rx_mgmt_action(struct wlantest *wt, const u8 *data, size_t len,
}
switch (mgmt->u.action.category) {
+ case WLAN_ACTION_FT:
+ rx_mgmt_action_ft(wt, sta, mgmt, len, valid);
+ break;
case WLAN_ACTION_SA_QUERY:
rx_mgmt_action_sa_query(wt, sta, mgmt, len, valid);
break;
diff --git a/wlantest/wlantest.h b/wlantest/wlantest.h
index 4e313e0..9324aa9 100644
--- a/wlantest/wlantest.h
+++ b/wlantest/wlantest.h
@@ -71,6 +71,8 @@ struct wlantest_sta {
int rsn_capab;
u8 anonce[32]; /* ANonce from the previous EAPOL-Key msg 1/4 or 3/4 */
u8 snonce[32]; /* SNonce from the previous EAPOL-Key msg 2/4 */
+ u8 pmk_r0[PMK_LEN];
+ u8 pmk_r0_name[WPA_PMK_NAME_LEN];
struct wpa_ptk ptk; /* Derived PTK */
int ptk_set;
struct wpa_ptk tptk; /* Derived PTK during rekeying */