When Peap Stops Working
My WiFi broke on a Tuesday afternoon, 13:29 IST, April 22, and the daemon I’d installed specifically for its reliability couldn’t reconnect. Chasing why pulled me through three layers of misconfiguration: a rotated server certificate, a deprecated authentication method, and a hash protocol that’s been on borrowed time for a decade. Permissive software would have kept me online without ever telling me any of this had happened.
In a hostel with dense access-point coverage, roaming gets noisy. As
you walk between buildings, the supplicant program on your device
scans for the strongest signal and decides when to switch. Standing
between several nodes all broadcasting iitk-sec, a supplicant like
wpa_supplicant
will oscillate between them on marginal signal differences and
degrade your connection. I had migrated my machine to
iwd (iNet Wireless Daemon)
to avoid exactly this, its
newer roaming algorithm
is less twitchy.
This is the divide between permissive and strict software.
wpa_supplicant is permissive: it tolerates unsafe states and
insecure fallbacks to keep the appearance of functionality. iwd is
strict, a rigid state machine that halts the moment something
doesn’t match.
In simpler terms: my laptop and the campus WiFi have to agree on how
to authenticate. That day, they disagreed. Because iwd refuses
unsafe fallbacks, the connection just failed.
How campus WiFi authenticates you
Enterprise WiFi like iitk-sec uses the
Extensible Authentication Protocol (EAP)
for negotiation. It happens at
layer 2, so before
you ever touch the internet your laptop has to prove its identity to
a central server. Three pieces are in play:
The bouncer (RADIUS). The server that checks your credentials against an identity store such as a directory service like Active Directory.
The tunnel (PEAP or TTLS). An encrypted TLS channel between your laptop and the RADIUS server, like HTTPS, but for the authentication handshake. PEAP and TTLS are the two common choices.
The payload (the inner method). A second protocol that runs inside that tunnel and actually verifies your password. PEAP almost always uses MSCHAPv2, a cryptographic challenge–response. TTLS is more flexible and supports methods like PAP, which transmits the password as plaintext inside the tunnel.
The certificate validation failure
Checking the kernel logs revealed the first issue:
PEAP: Tunnel has disconnected with alert: bad_certificate
The CC’s setup guide tells you to set the CA certificate to “Do not
validate” if the system certificate fails. wpa_supplicant lets you
do that. iwd deliberately doesn’t expose the option, at least not
easily.
Certificate validation matters because skipping it leaves you open
to evil-twin attacks:
a device faking the iitk-sec SSID can intercept your
authentication and walk away with your credentials. iwd enforces
server-side identity verification to prevent that.
The most charitable read is that the CC had rotated the
RADIUS server certificate,
and iwd couldn’t validate the new chain against my certificate
store, so it terminated the connection.
Extracting the certificate
I needed the new certificate. The usual move would be
openssl s_client, but EAP runs at layer 2, before the system has
an IP, so there’s no
TCP
endpoint to query. I could have pulled the cert off another device,
but iwd itself made it easier.
Running iwd with the TLS debug flag flips on certificate dumping
in its ell
backend, and the rejected server certificate ends up in /tmp:
sudo IWD_TLS_DEBUG=1 /usr/lib/iwd/iwd -d
After triggering a connection attempt, the fix is three steps:
- Move
iwd-tls-debug-server-cert.pemfrom/tmpto/etc/ssl/certs/iitk-radius.pem. - Point the
iwdprofile at it explicitly. - Mark the file immutable with
chattr +iso NetworkManager (which I still run on top ofiwd) can’t overwrite it.
Restart, retry, and the TLS tunnel comes up:
TTLS: tls_rsa_verify:240 Peer signature verified
But the connection still dropped.
The protocol shift
The real failure was deeper in the EAP negotiation:
EAP server tried method 4 while client was configured for method 25
EAP completed with eapFail
The server rejected PEAP
(Method 25)
and proposed EAP-MD5 (Method 4) instead. iwd correctly refused.
In enterprise networks, EAP-MD5 is what gets offered when nothing
better matches, a default that triggers when the server’s modern
config breaks. Refusing it is the right call, EAP-MD5 has no mutual
authentication. The server can verify you, but you can’t verify the
server.
But why would a server that negotiated PEAP that morning suddenly reject it that afternoon?
I don’t have access to the CC servers, so the exact cause isn’t confirmable. It could be a misconfigured policy update. But there’s a more interesting explanation in how PEAP authenticates the inside of its tunnel. PEAP wraps MSCHAPv2, and to evaluate an MSCHAPv2 challenge the RADIUS backend has to compute the response itself, which means it needs either the plaintext password or an NT-hash-equivalent credential on hand.
Unsalted NT hashes are a well-known liability, and modern identity providers and LDAP backends strongly prefer irreversible ones. There are caching workarounds that keep MSCHAPv2 working in mixed environments, but the most charitable read here is that the CC tightened backend hashing and MSCHAPv2 collapsed as a side effect. Once MSCHAPv2 is unavailable, PEAP, which has no other inner method to fall back to, fails along with it.
The TTLS-PAP solution
If MSCHAPv2 is gone, the only remaining option is to switch outer methods. The CC’s own guide already lists TTLS as a fallback, so I switched to EAP-TTLS with PAP inside. PAP transmits the password as plaintext through the TLS tunnel, which lets the server hash it on the fly and compare against whatever the modern IdP stores.
The catch: this shifts the entire security burden onto the TLS
tunnel. Skip certificate validation and you’re handing your password
to anyone running a fake AP. But because iwd had already forced me
to validate the server’s identity in step one, the tradeoff was
actually safe.
Updating the iwd profile:
[Security]
EAP-Method=TTLS
EAP-Identity=username
EAP-TTLS-Phase2-Method=Tunneled-PAP
EAP-TTLS-Phase2-Identity=username
EAP-TTLS-Phase2-Password=password
EAP-TTLS-CACert=/etc/ssl/certs/iitk-radius.pem
Restart the service. The handshake completes. The interface transitions to connected.
Conclusion
Using wpa_supplicant with “Do not validate” and letting it
silently sleepwalk through insecure fallbacks would have been
easier. But permissive software obscures the underlying reality.
wpa_supplicant would have kept me online. iwd forced me to
understand why I wasn’t.
Because iwd enforces a strict state machine instead of falling
back to insecure defaults, it forced me to look at the actual
exchange — and what came out was a clear picture of what had shifted
on the other end.
Permissive software hides broken systems. Strict software forces you to fix them.