You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I have a working WPA2-Enterprise (PEAP / MSCHAPv2) implementation for itlwm + HeliPort and wanted to check whether there's interest before turning it into PRs.
Status: tested on my university network (Texas A&M TAMU_WiFi, PEAP/MSCHAPv2). Initial connect, "Remember this network" + auto-join at login, and in-session reauthentication all work. So far it's one network on one machine:
Initial connect: ~170 ms of EAP after association; reauthentication: ~110 ms of EAP plus a rekey 4-way, with 0% ping loss during it
Design
I read @zxystd's comment in itlwm#101 about not wanting certificate handling in itlwm.kext, and this keeps it out of the kext. Everything EAP lives in HeliPort (userspace): TLS, certificate trust, credentials, and the EAP state machine. The kext only moves frames and installs the resulting PMK.
HeliPort (userspace)
Vendored hostap eap_peer + internal TLS (BSD license, no OpenSSL). PEAP outer, MSCHAPv2 inner only; other methods are NAK'd.
Certificate trust is trust-on-first-use: the first connection runs a probe-only TLS handshake, shows the server certificate (subject + SHA-256), and on "Trust" pins it per SSID. Later connections verify the pin inside hostap (hash://server/sha256/...) before phase 2, so credentials are only ever sent to the pinned certificate.
Credentials stay in the Keychain via the existing CredentialsManager.
EAPOL is received through a small privileged helper (SMJobBless) that opens a BPF fd filtered to EtherType 0x888E and hands it to the app. The helper is only (re)installed when the bundled copy differs, so auto-join doesn't prompt.
itlwm (kext): small, transport-only changes
ieee80211_enqueue_data: for 802.1X AKMs, pass non-Key EAPOL frames (EAP-Packet/Start/Logoff) up the normal input path so userspace can see them. EAPOL-Key frames stay in-kernel for the 4-way handshake. Today the non-AirportItlwm build drops these in ieee80211_eapol_key_input().
New user-client ioctls, appended so existing IDs are unchanged:
ASSOCIATE_ENTERPRISE: RSN with AKM 802.1X and no PSK.
WPA_KEY: delivers the PMK and adds it to the PMKSA cache, the same path as OpenBSD's SIOCS80211KEYAVAIL. The existing 4-way code then finds it with no changes. A failure status deauths.
TX_EAPOL: queues a userspace-built EAPOL frame on the driver's send queue. This is needed because the link stays down until the 4-way handshake and macOS drops BPF writes on a down interface. It only accepts EtherType 0x888E.
The PMK is cached under the negotiated AKM, and enterprise association requests AKM 802.1X only, so no SHA256-802.1X / 11w path is involved.
Bugs found along the way (separable, happy to send these first)
ItlNetworkUserClient::externalMethod bounds check is selector > IOCTL_ID_MAX, so selector == IOCTL_ID_MAX indexes past sMethods[] and calls through a garbage/NULL pointer (kernel panic). It should be >=.
ClientKit get_platform_info() builds driver_version + " " + fw_version with strcpy/strcat into a 32-byte field, which smashes the caller's stack once the version string gets a little longer.
Limitations / open questions
PEAP/MSCHAPv2 only (no EAP-TLS/TTLS), WPA2-Enterprise only (no WPA3-Enterprise / SHA256 AKM), itlwm only (not AirportItlwm, which has its own supplicant path).
OpenBSD's ieee80211_recv_4way_msg1 enforces the replay counter on Message 1. After a reauth my AP reused the previous counter, so the rekey took one AP retransmit (~1 s). wpa_supplicant doesn't enforce this on Message 1. I left it alone.
It needs a privileged helper for BPF. If you'd prefer frames delivered through the user client instead of BPF, I can move RX there too.
Would you be open to this? If so, how would you like it split? My plan was: (1) the two bug fixes, (2) the itlwm transport/ioctl changes, (3) the HeliPort supplicant/helper/UI.
The design is the one I described above, with one change: there's no privileged helper anymore. EAPOL frames go through new itlwm user-client calls, so HeliPort works as an ordinary unsigned build.
Until these are merged, there's an unofficial prebuilt itlwm.kext + HeliPort.app on my releases page: https://github.com/dantdmdarealguy/itlwm/releases (current build: v2.4.0-eap2). The two only work together, and only with itlwm (not AirportItlwm). It's been tested on one network (Texas A&M, PEAP/MSCHAPv2) with an AC 9560. If you try it on your eduroam or company network, please report what happened here: the network, your card, and whether it connected.
Activity
dantdmdarealguy commentedon Sep 26, 2026
I have a working WPA2-Enterprise (PEAP / MSCHAPv2) implementation for itlwm + HeliPort and wanted to check whether there's interest before turning it into PRs.
Status: tested on my university network (Texas A&M
TAMU_WiFi, PEAP/MSCHAPv2). Initial connect, "Remember this network" + auto-join at login, and in-session reauthentication all work. So far it's one network on one machine:Design
I read @zxystd's comment in itlwm#101 about not wanting certificate handling in
itlwm.kext, and this keeps it out of the kext. Everything EAP lives in HeliPort (userspace): TLS, certificate trust, credentials, and the EAP state machine. The kext only moves frames and installs the resulting PMK.HeliPort (userspace)
eap_peer+ internal TLS (BSD license, no OpenSSL). PEAP outer, MSCHAPv2 inner only; other methods are NAK'd.hash://server/sha256/...) before phase 2, so credentials are only ever sent to the pinned certificate.CredentialsManager.itlwm (kext): small, transport-only changes
ieee80211_enqueue_data: for 802.1X AKMs, pass non-Key EAPOL frames (EAP-Packet/Start/Logoff) up the normal input path so userspace can see them. EAPOL-Key frames stay in-kernel for the 4-way handshake. Today the non-AirportItlwm build drops these inieee80211_eapol_key_input().ASSOCIATE_ENTERPRISE: RSN with AKM 802.1X and no PSK.WPA_KEY: delivers the PMK and adds it to the PMKSA cache, the same path as OpenBSD'sSIOCS80211KEYAVAIL. The existing 4-way code then finds it with no changes. A failure status deauths.TX_EAPOL: queues a userspace-built EAPOL frame on the driver's send queue. This is needed because the link stays down until the 4-way handshake and macOS drops BPF writes on a down interface. It only accepts EtherType 0x888E.Bugs found along the way (separable, happy to send these first)
ItlNetworkUserClient::externalMethodbounds check isselector > IOCTL_ID_MAX, soselector == IOCTL_ID_MAXindexes pastsMethods[]and calls through a garbage/NULL pointer (kernel panic). It should be>=.get_platform_info()buildsdriver_version + " " + fw_versionwithstrcpy/strcatinto a 32-byte field, which smashes the caller's stack once the version string gets a little longer.Limitations / open questions
itlwmonly (not AirportItlwm, which has its own supplicant path).ieee80211_recv_4way_msg1enforces the replay counter on Message 1. After a reauth my AP reused the previous counter, so the rekey took one AP retransmit (~1 s). wpa_supplicant doesn't enforce this on Message 1. I left it alone.Would you be open to this? If so, how would you like it split? My plan was: (1) the two bug fixes, (2) the itlwm transport/ioctl changes, (3) the HeliPort supplicant/helper/UI.
Add WPA2-Enterprise (PEAP/MSCHAPv2) support
Add WPA2-Enterprise (PEAP/MSCHAPv2) support
dantdmdarealguy commentedon Oct 5, 2026
WPA2-Enterprise (PEAP/MSCHAPv2) support is now up as PRs:
The design is the one I described above, with one change: there's no privileged helper anymore. EAPOL frames go through new itlwm user-client calls, so HeliPort works as an ordinary unsigned build.
Until these are merged, there's an unofficial prebuilt
itlwm.kext+HeliPort.appon my releases page: https://github.com/dantdmdarealguy/itlwm/releases (current build: v2.4.0-eap2). The two only work together, and only with itlwm (not AirportItlwm). It's been tested on one network (Texas A&M, PEAP/MSCHAPv2) with an AC 9560. If you try it on your eduroam or company network, please report what happened here: the network, your card, and whether it connected.