Skip to content

Support 11w protected management frames #676

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 49 additions & 2 deletions AirportItlwm/AirportItlwm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -185,15 +185,15 @@ void AirportItlwm::associateSSID(uint8_t *ssid, uint32_t ssid_len, const struct
wpa.i_protos = IEEE80211_WPA_PROTO_WPA1 | IEEE80211_WPA_PROTO_WPA2;
}

if (authtype_upper & (APPLE80211_AUTHTYPE_WPA_PSK | APPLE80211_AUTHTYPE_WPA2_PSK)) {
if (authtype_upper & (APPLE80211_AUTHTYPE_WPA_PSK | APPLE80211_AUTHTYPE_WPA2_PSK | APPLE80211_AUTHTYPE_SHA256_PSK)) {
XYLog("%s %d\n", __FUNCTION__, __LINE__);
wpa.i_akms |= IEEE80211_WPA_AKM_PSK | IEEE80211_WPA_AKM_SHA256_PSK;
wpa.i_enabled = 1;
memcpy(ic->ic_psk, key, sizeof(ic->ic_psk));
ic->ic_flags |= IEEE80211_F_PSK;
ieee80211_ioctl_setwpaparms(ic, &wpa);
}
if (authtype_upper & (APPLE80211_AUTHTYPE_WPA | APPLE80211_AUTHTYPE_WPA2)) {
if (authtype_upper & (APPLE80211_AUTHTYPE_WPA | APPLE80211_AUTHTYPE_WPA2 | APPLE80211_AUTHTYPE_SHA256_8021X)) {
XYLog("%s %d\n", __FUNCTION__, __LINE__);
wpa.i_akms |= IEEE80211_WPA_AKM_8021X | IEEE80211_WPA_AKM_SHA256_8021X;
wpa.i_enabled = 1;
Expand Down Expand Up @@ -313,6 +313,53 @@ void AirportItlwm::setGTK(const u_int8_t *gtk, size_t key_len, u_int8_t kid, u_i
}
}

void AirportItlwm::setIGTK(const u_int8_t *igtk, size_t key_len, u_int8_t kid, u_int8_t *rsc) {
struct ieee80211com *ic = fHalService->get80211Controller();
struct ieee80211_node * ni = ic->ic_bss;
struct ieee80211_key *k;
int keylen;

if (igtk != NULL) {
/* check that the IGTK KDE is valid */
keylen = ieee80211_cipher_keylen(ni->ni_rsngroupmgmtcipher);
if (key_len != keylen) {
XYLog("IGTK length mismatch. expected %d, got %zu\n", keylen, key_len);
return;
}
if (kid != 4 && kid != 5) {
XYLog("unsupported IGTK id %u\n", kid);
return;
}
/* map GTK to 802.11 key */
k = &ic->ic_nw_keys[kid];
if (k->k_cipher == IEEE80211_CIPHER_NONE || k->k_len != keylen || memcmp(k->k_key, igtk, keylen) != 0) {
memset(k, 0, sizeof(*k));
k->k_id = kid; /* either 4 or 5 */
k->k_cipher = ni->ni_rsngroupmgmtcipher;
k->k_flags = IEEE80211_KEY_IGTK;
k->k_mgmt_rsc = LE_READ_6(rsc); /* IPN */
k->k_len = keylen;
memcpy(k->k_key, igtk, k->k_len);
/* install the IGTK */
if ((*ic->ic_set_key)(ic, ni, k) != 0) {
XYLog("setting IGTK failed\n");
return;
}
else {
XYLog("setting IGTK successfully\n");
}
}

/* use MFP if we both support it */
if ((ic->ic_caps & IEEE80211_C_MFP) &&
(ni->ni_rsncaps & IEEE80211_RSNCAP_MFPC)) {
ni->ni_flags |= IEEE80211_NODE_MFP;
ni->ni_flags |= IEEE80211_NODE_TXMGMTPROT;
ni->ni_flags |= IEEE80211_NODE_RXMGMTPROT;
ic->ic_igtk_kid = kid;
}
}
}

bool AirportItlwm::
createMediumTables(const IONetworkMedium **primary)
Expand Down
1 change: 1 addition & 0 deletions AirportItlwm/AirportItlwm.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ IOReturn set##REQ(OSObject *object, struct DATA_TYPE *data);
void associateSSID(uint8_t *ssid, uint32_t ssid_len, const struct ether_addr &bssid, uint32_t authtype_lower, uint32_t authtype_upper, uint8_t *key, uint32_t key_len, int key_index);
void setPTK(const u_int8_t *key, size_t key_len);
void setGTK(const u_int8_t *key, size_t key_len, u_int8_t kid, u_int8_t *rsc);
void setIGTK(const u_int8_t *key, size_t key_len, u_int8_t kid, u_int8_t *rsc);
void watchdogAction(IOTimerEventSource *timer);
bool initPCIPowerManagment(IOPCIDevice *provider);
static IOReturn tsleepHandler(OSObject* owner, void* arg0 = 0, void* arg1 = 0, void* arg2 = 0, void* arg3 = 0);
Expand Down
4 changes: 4 additions & 0 deletions AirportItlwm/AirportSTAIOCTL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,10 @@ setCIPHER_KEY(OSObject *object, struct apple80211_key *key)
setGTK(key->key, key->key_len, key->key_index, key->key_rsc);
getNetworkInterface()->postMessage(APPLE80211_M_RSN_HANDSHAKE_DONE);
break;
case 64: // IGTK
setIGTK(key->key, key->key_len, key->key_index, key->key_rsc);
getNetworkInterface()->postMessage(APPLE80211_M_RSN_HANDSHAKE_DONE);
break;
}
break;
case APPLE80211_CIPHER_PMK:
Expand Down
6 changes: 4 additions & 2 deletions itl80211/openbsd/net80211/ieee80211_crypto.c
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,8 @@ ieee80211_decrypt(struct ieee80211com *ic, mbuf_t m0,
/* find key for decryption */
k = ieee80211_get_rxkey(ic, m0, ni);
if (k == NULL || (k->k_flags & IEEE80211_KEY_SWCRYPTO) == 0) {
XYLog("%s: BUG! key unset for sw crypto. k_id: %d k_cipher: %d k_flags: %d\n",
__FUNCTION__, k ? k->k_id : -1, k ? k->k_cipher : -1, k ? k->k_flags : -1);
mbuf_freem(m0);
return NULL;
}
Expand Down Expand Up @@ -384,7 +386,7 @@ ieee80211_kdf(const u_int8_t *key, size_t key_len, const u_int8_t *label,
HMAC_SHA256_Init(&ctx, key, key_len);
iter = htole16(i);
HMAC_SHA256_Update(&ctx, (u_int8_t *)&iter, sizeof iter);
HMAC_SHA256_Update(&ctx, label, label_len);
HMAC_SHA256_Update(&ctx, label, strlen((const char*)label));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is wrong, what about ieee80211_prf?

Copy link
Contributor Author

@pigworlds pigworlds Sep 14, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is one of the most confusing part. I didn't read the original 11w specification. I learnt this from reading the wpa_supplicant.
There are 2 major differences compare between HMAC-SHA1 PRF vs HMAC-SHA256 KDF/PRF.

  • When using the Pairwise key expansion label, there are differences counting the string length. In SHA1 PRF, the label is taken as Pairwise key expansion\0. In SHA256 PRF, the label is taken as Pairwise key expansion. This one-byte difference is causing incorrect key being generated.
  • The SHA256 KDF is also taken the number of output bits as part of its data, where the SHA1 PRF doesn't. This make difference since SHA256 KDF is expecting the output PTK to be 48 bytes, the previous code is passing as 64 bytes. Note, this PTK length should also depend on the cipher chosen.

HMAC_SHA256_Update(&ctx, context, context_len);
HMAC_SHA256_Update(&ctx, (u_int8_t *)&length, sizeof length);
if (len < SHA256_DIGEST_LENGTH) {
Expand Down Expand Up @@ -424,7 +426,7 @@ ieee80211_derive_ptk(enum ieee80211_akm akm, const u_int8_t *pmk,

kdf = ieee80211_is_sha256_akm(akm) ? ieee80211_kdf : ieee80211_prf;
(*kdf)(pmk, IEEE80211_PMK_LEN, (const u_int8_t *)"Pairwise key expansion", 23,
buf, sizeof buf, (u_int8_t *)ptk, sizeof(*ptk));
buf, sizeof buf, (u_int8_t *)ptk, kdf ? 48 : sizeof(*ptk));
}

static void
Expand Down
29 changes: 19 additions & 10 deletions itl80211/openbsd/net80211/ieee80211_input.c
Original file line number Diff line number Diff line change
Expand Up @@ -651,16 +651,25 @@ ieee80211_inputm(struct _ifnet *ifp, mbuf_t m, struct ieee80211_node *ni,
if (subtype == IEEE80211_FC0_SUBTYPE_DISASSOC ||
subtype == IEEE80211_FC0_SUBTYPE_DEAUTH ||
subtype == IEEE80211_FC0_SUBTYPE_ACTION) {
if (!IEEE80211_IS_MULTICAST(wh->i_addr1) &&
!(wh->i_fc[1] & IEEE80211_FC1_PROTECTED)) {
/* unicast mgmt not encrypted */
goto out;
}
/* do software decryption */
m = ieee80211_decrypt(ic, m, ni);
if (m == NULL) {
/* XXX stats */
goto out;
if (!(rxi->rxi_flags & IEEE80211_RXI_HWDEC)) {
if (!IEEE80211_IS_MULTICAST(wh->i_addr1) &&
!(wh->i_fc[1] & IEEE80211_FC1_PROTECTED)) {
/* unicast mgmt not encrypted */
ic->ic_stats.is_rx_unencrypted++;
ic->ic_stats.is_rx_mgtdiscard++;
goto out;
}
/* do software decryption */
m = ieee80211_decrypt(ic, m, ni);
if (m == NULL) {
/* XXX stats */
ic->ic_stats.is_rx_wepfail++;
goto out;
}
} else {
m = ieee80211_input_hwdecrypt(ic, ni, m, rxi);
if (m == NULL)
goto err;
}
wh = mtod(m, struct ieee80211_frame *);
}
Expand Down
4 changes: 3 additions & 1 deletion itl80211/openbsd/net80211/ieee80211_output.c
Original file line number Diff line number Diff line change
Expand Up @@ -224,8 +224,10 @@ ieee80211_mgmt_output(struct _ifnet *ifp, struct ieee80211_node *ni,
* XXX could use an mbuf flag..
*/
if (IEEE80211_IS_MULTICAST(wh->i_addr1) ||
(ni->ni_flags & IEEE80211_NODE_TXMGMTPROT))
(ni->ni_flags & IEEE80211_NODE_TXMGMTPROT)) {
XYLog("%s %d type=%d going to protect.\n", __FUNCTION__, __LINE__, type);
wh->i_fc[1] |= IEEE80211_FC1_PROTECTED;
}
}

if (ifp->if_flags & IFF_DEBUG) {
Expand Down
6 changes: 6 additions & 0 deletions itl80211/openbsd/net80211/ieee80211_pae_input.c
Original file line number Diff line number Diff line change
Expand Up @@ -673,6 +673,9 @@ ieee80211_recv_4way_msg3(struct ieee80211com *ic,
reason = IEEE80211_REASON_AUTH_LEAVE;
goto deauth;
}
ni->ni_flags |= IEEE80211_NODE_TXMGMTPROT;
ni->ni_flags |= IEEE80211_NODE_RXMGMTPROT;
ic->ic_igtk_kid = kid;
}
}
if (info & EAPOL_KEY_INSTALL)
Expand Down Expand Up @@ -962,6 +965,9 @@ ieee80211_recv_rsn_group_msg1(struct ieee80211com *ic,
reason = IEEE80211_REASON_AUTH_LEAVE;
goto deauth;
}
ni->ni_flags |= IEEE80211_NODE_TXMGMTPROT;
ni->ni_flags |= IEEE80211_NODE_RXMGMTPROT;
ic->ic_igtk_kid = kid;
}
}
if (info & EAPOL_KEY_SECURE) {
Expand Down
8 changes: 6 additions & 2 deletions itlwm/hal_iwm/mac80211.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1734,6 +1734,7 @@ iwm_tx(struct iwm_softc *sc, mbuf_t m, struct ieee80211_node *ni, int ac)
if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
k = ieee80211_get_txkey(ic, wh, ni);
if ((k->k_flags & IEEE80211_KEY_GROUP) ||
(k->k_flags & IEEE80211_KEY_IGTK) ||
(k->k_cipher != IEEE80211_CIPHER_CCMP)) {
if ((m = ieee80211_encrypt(ic, m, k)) == NULL)
return ENOBUFS;
Expand Down Expand Up @@ -2603,6 +2604,7 @@ iwm_set_key(struct ieee80211com *ic, struct ieee80211_node *ni,
ItlIwm *that = container_of(sc, ItlIwm, com);

if ((k->k_flags & IEEE80211_KEY_GROUP) ||
(k->k_flags & IEEE80211_KEY_IGTK) ||
k->k_cipher != IEEE80211_CIPHER_CCMP) {
/* Fallback to software crypto for other ciphers. */
return (ieee80211_set_key(ic, ni, k));
Expand Down Expand Up @@ -2659,9 +2661,10 @@ iwm_delete_key(struct ieee80211com *ic, struct ieee80211_node *ni,
ItlIwm *that = container_of(sc, ItlIwm, com);

if ((k->k_flags & IEEE80211_KEY_GROUP) ||
(k->k_flags & IEEE80211_KEY_IGTK) ||
(k->k_cipher != IEEE80211_CIPHER_CCMP)) {
/* Fallback to software crypto for other ciphers. */
ieee80211_delete_key(ic, ni, k);
ieee80211_delete_key(ic, ni, k);
return;
}

Expand Down Expand Up @@ -4852,7 +4855,8 @@ iwm_attach(struct iwm_softc *sc, struct pci_attach_args *pa)
IEEE80211_C_SCANALLBAND | /* device scans all bands at once */
IEEE80211_C_MONITOR | /* monitor mode supported */
IEEE80211_C_SHSLOT | /* short slot time supported */
IEEE80211_C_SHPREAMBLE; /* short preamble supported */
IEEE80211_C_SHPREAMBLE | /* short preamble supported */
IEEE80211_C_MFP; /* management frame protection 11w supported */

ic->ic_htcaps = IEEE80211_HTCAP_SGI20;
ic->ic_htcaps |=
Expand Down
15 changes: 11 additions & 4 deletions itlwm/hal_iwn/ItlIwn.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -495,7 +495,8 @@ iwn_attach(struct iwn_softc *sc, struct pci_attach_args *pa)
IEEE80211_C_MONITOR | /* monitor mode supported */
IEEE80211_C_SHSLOT | /* short slot time supported */
IEEE80211_C_SHPREAMBLE | /* short preamble supported */
IEEE80211_C_PMGT; /* power saving supported */
IEEE80211_C_PMGT | /* power saving supported */
IEEE80211_C_MFP; /* management frame protection 11w supported */
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not all of the DVM cards' firmwares support 11w, original iwlwifi code says:

/*
 * Enable 11w if advertised by firmware and software crypto
 * is not enabled (as the firmware will interpret some mgmt
 * packets, so enabling it with software crypto isn't safe)
 */
if (priv->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_MFP &&
    !iwlwifi_mod_params.swcrypto)
	ieee80211_hw_set(hw, MFP_CAPABLE);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You made a good point.

I quickly checked my N 6205 card, the tlv_feature_flags is 0x0b, and it doesn't include the bit IWN_UCODE_TLV_FLAGS_MFP (1<<2). It looks like the firmware doesn't tell support 11w, and it is actually working on my setup. It is unclear to me what's the best way to determine this feature flag.

I'll leave the code for iwn as is without testing the firmware feature flags for now. May be there are some corner cases to be discovered.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I know why the dvm firmware doesn't support 11w. The firmware doesn't support install igtk hw keys.
In the current implementation, group key and the new igtk are done in software crypto in the net80211 stack for both iwn and iwm. Unicast key is handled in firmware. With this hybrid approach, we can consider the driver is MFP capable.


/* No optional HT features supported for now, */
ic->ic_htcaps = 0;
Expand Down Expand Up @@ -3517,17 +3518,21 @@ iwn_tx(struct iwn_softc *sc, mbuf_t m, struct ieee80211_node *ni)
if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
/* Retrieve key for TX. */
k = ieee80211_get_txkey(ic, wh, ni);
if (k->k_cipher != IEEE80211_CIPHER_CCMP) {
if ((k->k_flags & IEEE80211_KEY_GROUP) ||
(k->k_flags & IEEE80211_KEY_IGTK) ||
(k->k_cipher != IEEE80211_CIPHER_CCMP)) {
/* Do software encryption. */
if ((m = ieee80211_encrypt(ic, m, k)) == NULL)
return ENOBUFS;
/* 802.11 header may have moved. */
wh = mtod(m, struct ieee80211_frame *);
// totlen = m->m_pkthdr.len;
totlen = mbuf_pkthdr_len(m);

} else /* HW appends CCMP MIC. */
k = NULL; /* skip hardware crypto below */
} else {
/* HW appends CCMP MIC. */
totlen += IEEE80211_CCMP_HDRLEN;
}
}

data->totlen = totlen;
Expand Down Expand Up @@ -5855,6 +5860,7 @@ iwn_set_key(struct ieee80211com *ic, struct ieee80211_node *ni,
uint16_t kflags;

if ((k->k_flags & IEEE80211_KEY_GROUP) ||
(k->k_flags & IEEE80211_KEY_IGTK) ||
k->k_cipher != IEEE80211_CIPHER_CCMP)
return ieee80211_set_key(ic, ni, k);

Expand Down Expand Up @@ -5884,6 +5890,7 @@ iwn_delete_key(struct ieee80211com *ic, struct ieee80211_node *ni,
struct iwn_node_info node;

if ((k->k_flags & IEEE80211_KEY_GROUP) ||
(k->k_flags & IEEE80211_KEY_IGTK) ||
k->k_cipher != IEEE80211_CIPHER_CCMP) {
/* See comment about other ciphers above. */
ieee80211_delete_key(ic, ni, k);
Expand Down