diff --git a/AirportItlwm/AirportItlwm.cpp b/AirportItlwm/AirportItlwm.cpp index 3b426cd8c..c356aa23a 100644 --- a/AirportItlwm/AirportItlwm.cpp +++ b/AirportItlwm/AirportItlwm.cpp @@ -185,7 +185,7 @@ 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; @@ -193,7 +193,7 @@ void AirportItlwm::associateSSID(uint8_t *ssid, uint32_t ssid_len, const struct 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; @@ -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) diff --git a/AirportItlwm/AirportItlwm.hpp b/AirportItlwm/AirportItlwm.hpp index 470a5903b..f47b06312 100644 --- a/AirportItlwm/AirportItlwm.hpp +++ b/AirportItlwm/AirportItlwm.hpp @@ -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); diff --git a/AirportItlwm/AirportSTAIOCTL.cpp b/AirportItlwm/AirportSTAIOCTL.cpp index b3d0e34ba..b7c39d3df 100644 --- a/AirportItlwm/AirportSTAIOCTL.cpp +++ b/AirportItlwm/AirportSTAIOCTL.cpp @@ -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: diff --git a/itl80211/openbsd/net80211/ieee80211_crypto.c b/itl80211/openbsd/net80211/ieee80211_crypto.c index 9aa4845a5..cccf7f98c 100644 --- a/itl80211/openbsd/net80211/ieee80211_crypto.c +++ b/itl80211/openbsd/net80211/ieee80211_crypto.c @@ -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; } @@ -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)); HMAC_SHA256_Update(&ctx, context, context_len); HMAC_SHA256_Update(&ctx, (u_int8_t *)&length, sizeof length); if (len < SHA256_DIGEST_LENGTH) { @@ -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 diff --git a/itl80211/openbsd/net80211/ieee80211_input.c b/itl80211/openbsd/net80211/ieee80211_input.c index e893ed287..7e0620770 100644 --- a/itl80211/openbsd/net80211/ieee80211_input.c +++ b/itl80211/openbsd/net80211/ieee80211_input.c @@ -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 *); } diff --git a/itl80211/openbsd/net80211/ieee80211_output.c b/itl80211/openbsd/net80211/ieee80211_output.c index 4526d7748..dfce93e23 100644 --- a/itl80211/openbsd/net80211/ieee80211_output.c +++ b/itl80211/openbsd/net80211/ieee80211_output.c @@ -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) { diff --git a/itl80211/openbsd/net80211/ieee80211_pae_input.c b/itl80211/openbsd/net80211/ieee80211_pae_input.c index 7e464bd7e..a8039c7c2 100644 --- a/itl80211/openbsd/net80211/ieee80211_pae_input.c +++ b/itl80211/openbsd/net80211/ieee80211_pae_input.c @@ -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) @@ -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) { diff --git a/itlwm/hal_iwm/mac80211.cpp b/itlwm/hal_iwm/mac80211.cpp index a7c2ca172..306ff2a82 100644 --- a/itlwm/hal_iwm/mac80211.cpp +++ b/itlwm/hal_iwm/mac80211.cpp @@ -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; @@ -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)); @@ -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; } @@ -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 |= diff --git a/itlwm/hal_iwn/ItlIwn.cpp b/itlwm/hal_iwn/ItlIwn.cpp index 5980fc4bf..8b9426882 100644 --- a/itlwm/hal_iwn/ItlIwn.cpp +++ b/itlwm/hal_iwn/ItlIwn.cpp @@ -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 */ /* No optional HT features supported for now, */ ic->ic_htcaps = 0; @@ -3517,7 +3518,9 @@ 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; @@ -3525,9 +3528,11 @@ iwn_tx(struct iwn_softc *sc, mbuf_t m, struct ieee80211_node *ni) 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; @@ -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); @@ -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);