A WiFi outage and its relation to a DEF CON 20 talk
On April 22, Tuesday, 13:29 IST, my WiFi broke.This was unexpected since I had switched from my older
wpa_supplicant setup to
iwd in the to avoid the frequent
disconnection that happens. I live in a hostel with a lot of access points and
the supplicant program decides when to switch as one moves around. A supplicant
like wpa_supplicant
oscillates between points on marginal signal differences and leaves me
disconnected for some time . I migrated to
iwd to avoid this given its better
roaming algorithm which is less
twitchy.
How enterprise WiFi authentication works
Enterprise WiFi like iitk-sec uses the Extensible Authentication Protocol (EAP) for negotiation. It happens at layer 2, and thus the laptop has to prove its identity to the server before it connects with the general internet Then there is the bouncer (RADIUS) checking credentials against a directory service like Active Directory and the tunnel (PEAP or TTLS) creating an encrypted TLS channel between the laptop and the RADIUS server. And the there is the payload, the inner method actually verifying the password. PEAP almost always forces MSCHAPv2 as it’s used in my school. TTLS is flexible enough to allow protocols like PAP to pass plaintext straight down the tunnel.
Certificate issues
To check why I wasn’t connecting, the first thing I ran was dmesg, then
journalctl -u iwd. The logs had some answer in it, which I missed earlier.
PEAP: Tunnel has disconnected with alert: bad_certificate
My school’s Computer Center’s (the CC, which manages infra) setup guide states
to set the CA certificate to “Do not validate” if the system certificate fails.
wpa_supplicant lets you do that but iwd deliberately doesn’t expose the
option, at least not easily. I didn’t want to skip certificate validation as
that would leave me susceptible to evil-twin
attacks which is
when a device faking the iitk-sec SSID intercepts authentication and walks away
with the credentials. iwd is safer in this regard, enforcing server-side
identity verification. So what cound be the problem here? Among other things, I
guessed that the CC had changed the RADIUS server certificate, because of which
‘iwd’ couldn’t validate my connection as before.
I needed the new certificate then. I had some options at my hand, running
openssl s_client, but that didn’t work as EAP runs at layer 2 which is before
the system has an IP, so there’s no
TCP endpoint to
query. Or I could have pulled the cert off another device, but iwd itself
made it easier.
Running iwd with the TLS debug flag enables certificate dumping due to its
ell backend, which I got
to know reading the source, and the rejected server certificate ends up in
/tmp.
sudo IWD_TLS_DEBUG=1 /usr/lib/iwd/iwd -d
The fix involved moving iwd-tls-debug-server-cert.pem from /tmp to
/etc/ssl/certs/iitk-radius.pem and pointing the iwd profile at it
explicitly. Though
NetworkManager kept
overwriting it which stopped once I marked the file immutable with chattr +i.
I restarted, and the TLS tunnel came up
TTLS: tls_rsa_verify:240 Peer signature verified
Protocols switcheroo
I looked deeper and found more issues. Now with the EAP negotiation.
EAP server tried method 4 while client was configured for method 25 EAP
completed with eapFail
The server was rejecting PEAP (Method
25)
and proposing EAP-MD5 (Method 4) instead. iwd refused it, as it isn’t
particularly safe. (EAP-MD5 gets offered when nothing better is available)
The server was negotiating PEAP early morning. I don’t have access to the CC servers, so the exact cause isn’t confirmable. However, I found a detail in PEAP authentication that might have been causing the issue.
The RADIUS backend has to compute the response for the MSCHAPv2 challenge, which means it requires either the plaintext password or an NT-hash-equivalent credential on hand. MSCHAPv2 challenges are two one, and the device solves a challenge sending both the answer and password. And since this can’t work with one-way passwords, the RADIUS server had to have stored plaintext or unsalted NT-hashed passwords. The CC probably tightened backend hashing, unsalted NT hashes are a well-known liability. This could have led to MSCHAPv2, and thus PEAP being disallowed. More details on how MSCHAPv2 was broken can be found in this DEF CON 20 talk.
Resolve
So, MSCHAPv2 had to be scrapped, and PEAP with it. The CC guide lists TTLS as a
fallback, so I switched to
EAP-TTLS
with PAP. PAP also skips certificate validation, as it work by transmitting the
password as plaintext along the TLS tunnel, but since iwd already forces the
validation of the server’s identity in the first step, it’s should be fine.
Profile update
[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
After updating the profile and restarting the service, the handshake finished and the interface connected.
Surely, it would have been easier to use wpa_supplicant with “Do not
validate” and ignore the insecure fallbacks. But then I wouldn’t have gotten to
deepdive into network fundamentals. iwd forced me to fix and understand the
broken system by being less permisive.