diff options
author | Jouni Malinen <jouni.malinen@atheros.com> | 2010-11-19 16:48:33 +0200 |
---|---|---|
committer | Jouni Malinen <j@w1.fi> | 2010-11-19 16:48:33 +0200 |
commit | 2e4c34691b734e7239dacddf4a2c5739c72b4ec5 (patch) | |
tree | 8d430a3cdaa66281fc63f66d7f4fa9b5ec31f1b8 /wlantest | |
parent | 4adc5e0f0b58b12dd66dc7503a18d1e5737e97b8 (diff) | |
download | external_wpa_supplicant_8_ti-2e4c34691b734e7239dacddf4a2c5739c72b4ec5.zip external_wpa_supplicant_8_ti-2e4c34691b734e7239dacddf4a2c5739c72b4ec5.tar.gz external_wpa_supplicant_8_ti-2e4c34691b734e7239dacddf4a2c5739c72b4ec5.tar.bz2 |
wlantest: Add support for protecting injected broadcast frames
Diffstat (limited to 'wlantest')
-rw-r--r-- | wlantest/inject.c | 143 | ||||
-rw-r--r-- | wlantest/rx_data.c | 10 | ||||
-rw-r--r-- | wlantest/wlantest.h | 2 |
3 files changed, 145 insertions, 10 deletions
diff --git a/wlantest/inject.c b/wlantest/inject.c index cdfa37a..853dae1 100644 --- a/wlantest/inject.c +++ b/wlantest/inject.c @@ -17,6 +17,7 @@ #include "utils/common.h" #include "common/defs.h" #include "common/ieee802_11_defs.h" +#include "crypto/aes_wrap.h" #include "wlantest.h" @@ -83,6 +84,117 @@ static int is_robust_mgmt(u8 *frame, size_t len) } +static int wlantest_inject_bip(struct wlantest *wt, struct wlantest_bss *bss, + u8 *frame, size_t len, int incorrect_key) +{ + u8 *prot, *pos, *buf; + u8 mic[16]; + u8 dummy[16]; + int ret; + u16 fc; + struct ieee80211_hdr *hdr; + size_t plen; + + if (!bss->igtk_set[bss->igtk_idx]) + return -1; + + plen = len + 18; + prot = os_malloc(plen); + if (prot == NULL) + return -1; + os_memcpy(prot, frame, len); + pos = prot + len; + *pos++ = WLAN_EID_MMIE; + *pos++ = 16; + WPA_PUT_LE16(pos, bss->igtk_idx); + pos += 2; + inc_byte_array(bss->ipn[bss->igtk_idx], 6); + os_memcpy(pos, bss->ipn[bss->igtk_idx], 6); + pos += 6; + os_memset(pos, 0, 8); /* MIC */ + + buf = os_malloc(plen + 20 - 24); + if (buf == NULL) { + os_free(prot); + return -1; + } + + /* BIP AAD: FC(masked) A1 A2 A3 */ + hdr = (struct ieee80211_hdr *) frame; + fc = le_to_host16(hdr->frame_control); + fc &= ~(WLAN_FC_RETRY | WLAN_FC_PWRMGT | WLAN_FC_MOREDATA); + WPA_PUT_LE16(buf, fc); + os_memcpy(buf + 2, hdr->addr1, 3 * ETH_ALEN); + os_memcpy(buf + 20, prot + 24, plen - 24); + wpa_hexdump(MSG_MSGDUMP, "BIP: AAD|Body(masked)", buf, plen + 20 - 24); + /* MIC = L(AES-128-CMAC(AAD || Frame Body(masked)), 0, 64) */ + os_memset(dummy, 0x11, sizeof(dummy)); + if (omac1_aes_128(incorrect_key ? dummy : bss->igtk[bss->igtk_idx], + buf, plen + 20 - 24, mic) < 0) { + os_free(prot); + os_free(buf); + return -1; + } + os_free(buf); + + os_memcpy(pos, mic, 8); + wpa_hexdump(MSG_DEBUG, "BIP MMIE MIC", pos, 8); + + ret = inject_frame(wt->monitor_sock, prot, plen); + os_free(prot); + + return (ret < 0) ? -1 : 0; +} + + +static int wlantest_inject_prot_bc(struct wlantest *wt, + struct wlantest_bss *bss, + u8 *frame, size_t len, int incorrect_key) +{ + u8 *crypt; + size_t crypt_len; + int ret; + u8 dummy[64]; + u8 *pn; + struct ieee80211_hdr *hdr; + u16 fc; + int hdrlen; + + hdr = (struct ieee80211_hdr *) frame; + hdrlen = 24; + fc = le_to_host16(hdr->frame_control); + + if (!bss->gtk_len[bss->gtk_idx]) + return -1; + + if ((fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) == + (WLAN_FC_TODS | WLAN_FC_FROMDS)) + hdrlen += ETH_ALEN; + pn = bss->rsc[bss->gtk_idx]; + inc_byte_array(pn, 6); + + os_memset(dummy, 0x11, sizeof(dummy)); + if (bss->group_cipher == WPA_CIPHER_TKIP) + crypt = tkip_encrypt(incorrect_key ? dummy : + bss->gtk[bss->gtk_idx], + frame, len, hdrlen, NULL, pn, + bss->gtk_idx, &crypt_len); + else + crypt = ccmp_encrypt(incorrect_key ? dummy : + bss->gtk[bss->gtk_idx], + frame, len, hdrlen, NULL, pn, + bss->gtk_idx, &crypt_len); + + if (crypt == NULL) + return -1; + + ret = inject_frame(wt->monitor_sock, crypt, crypt_len); + os_free(crypt); + + return (ret < 0) ? -1 : 0; +} + + static int wlantest_inject_prot(struct wlantest *wt, struct wlantest_bss *bss, struct wlantest_sta *sta, u8 *frame, size_t len, int incorrect_key) @@ -98,15 +210,21 @@ static int wlantest_inject_prot(struct wlantest *wt, struct wlantest_bss *bss, u8 *qos = NULL; int hdrlen; - if (sta == NULL) - return -1; /* TODO: add support for group Data and BIP */ + hdr = (struct ieee80211_hdr *) frame; + hdrlen = 24; + fc = le_to_host16(hdr->frame_control); + + if (sta == NULL) { + if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT) + return wlantest_inject_bip(wt, bss, frame, len, + incorrect_key); + return wlantest_inject_prot_bc(wt, bss, frame, len, + incorrect_key); + } if (!sta->ptk_set) return -1; - hdr = (struct ieee80211_hdr *) frame; - hdrlen = 24; - fc = le_to_host16(hdr->frame_control); if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT) tid = 16; else if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_DATA) { @@ -168,9 +286,14 @@ int wlantest_inject(struct wlantest *wt, struct wlantest_bss *bss, if (prot == WLANTEST_INJECT_PROTECTED || prot == WLANTEST_INJECT_INCORRECT_KEY) { - if (!sta) { - wpa_printf(MSG_INFO, "Broadcast protection not yet " - "implemented"); + if (!sta && + ((WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && + !bss->igtk_set[bss->igtk_idx]) || + (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_DATA && + !bss->gtk_len[bss->gtk_idx]))) { + wpa_printf(MSG_INFO, "No GTK/IGTK known for " + MACSTR " to protect the injected " + "frame", MAC2STR(bss->bssid)); return -1; } if (sta && !sta->ptk_set) { @@ -185,10 +308,10 @@ int wlantest_inject(struct wlantest *wt, struct wlantest_bss *bss, protect = 1; else if (!sta) { if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_DATA && - (bss->gtk_len[1] || bss->gtk_len[2])) + bss->gtk_len[bss->gtk_idx]) protect = 1; if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && - (bss->igtk_set[4] || bss->igtk_set[5])) + bss->igtk_set[bss->igtk_idx]) protect = 1; } } diff --git a/wlantest/rx_data.c b/wlantest/rx_data.c index 56c4954..4e4e899 100644 --- a/wlantest/rx_data.c +++ b/wlantest/rx_data.c @@ -382,6 +382,7 @@ static void learn_kde_keys(struct wlantest_bss *bss, const u8 *buf, size_t len, bss->rsc[id][3] = rsc[2]; bss->rsc[id][4] = rsc[1]; bss->rsc[id][5] = rsc[0]; + bss->gtk_idx = id; wpa_hexdump(MSG_DEBUG, "RSC", bss->rsc[id], 6); } else { wpa_printf(MSG_INFO, "Invalid GTK KDE length %u", @@ -399,12 +400,21 @@ static void learn_kde_keys(struct wlantest_bss *bss, const u8 *buf, size_t len, wpa_printf(MSG_INFO, "Unexpected IGTK KeyID " "%u", id); } else { + const u8 *ipn; wpa_printf(MSG_DEBUG, "IGTK KeyID %u", id); wpa_hexdump(MSG_DEBUG, "IPN", ie.igtk + 2, 6); wpa_hexdump(MSG_DEBUG, "IGTK", ie.igtk + 8, 16); os_memcpy(bss->igtk[id], ie.igtk + 8, 16); bss->igtk_set[id] = 1; + ipn = ie.igtk + 2; + bss->ipn[id][0] = ipn[5]; + bss->ipn[id][1] = ipn[4]; + bss->ipn[id][2] = ipn[3]; + bss->ipn[id][3] = ipn[2]; + bss->ipn[id][4] = ipn[1]; + bss->ipn[id][5] = ipn[0]; + bss->igtk_idx = id; } } else { wpa_printf(MSG_INFO, "Invalid IGTK KDE length %u", diff --git a/wlantest/wlantest.h b/wlantest/wlantest.h index 14c31b7..7dd0109 100644 --- a/wlantest/wlantest.h +++ b/wlantest/wlantest.h @@ -91,9 +91,11 @@ struct wlantest_bss { struct dl_list pmk; /* struct wlantest_pmk */ u8 gtk[4][32]; size_t gtk_len[4]; + int gtk_idx; u8 rsc[4][6]; u8 igtk[6][16]; int igtk_set[6]; + int igtk_idx; u8 ipn[6][6]; u32 counters[NUM_WLANTEST_BSS_COUNTER]; }; |