Skip to content

Support EAP authentication #4

Open

Description

@williambj1
No description provided.

Activity

  1. added this to the v1.0.0 milestone on May 30, 2020
  2. modified the milestones: v1.0.0, v1.0.1 on Jul 16, 2020
  3. modified the milestones: v1.0.1, v1.0.2 on Sep 23, 2020
  4. removed this from the v1.0.2 milestone on Jan 15, 2021
  5. dantdmdarealguy commented on Sep 26, 2026

    @dantdmdarealguy

    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:

    • macOS 15.7.7, Intel Wireless-AC 9560 (8086:34F0, subsystem 0034), itlwm 2.4.0
    • 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

    1. 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().
    2. 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.
    3. 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.

  6. added 2 commits that reference this issue on Oct 5, 2026
    ec82c4e
    4b25552
  7. dantdmdarealguy commented on Oct 5, 2026

    @dantdmdarealguy

    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.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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions