If you don’t set a password on your wifi, then not only can anyone connect, but it’s not even encrypted. This means that even when an open network gives you a captive portal, that could actually be an attacker giving you a fake portal. Even if the portal is HTTPS, because you may be connected to https://evil-fake-portal.com.

That is solved in WPA3, where even open networks become encrypted.

Of course, the attacker can just set up a fake access point, and you’ll connect, none the wiser. Even if the network has a password, the attacker only needs to know that password in order to fake it.

Before WPA3, passwords can easily be brute forced offline. A few years ago I calculated that it would cost about $70 to crack the default generated 8 character random passwords used by a popular ISP here in London, using some GPUs in Google Cloud. I’m sure it’s cheaper now.

That’s potentially years of free use of your neighbours wifi, for just the cost of a couple of months of paying for your own.

But that’s illegal, of course. This post is about protecting you against these attacks, not performing them.

If you don’t want to mandate WPA3, but still not have a password, then you can do what some hacker conferences do, and set up WPA Enterprise network with username/password, and accept any username and password provided.

And if you do want a password, WPA Enterprise can be set up to make them not vulnerable to brute force.

WPA Enterprise also makes the network authenticate to the client, so password or not, nobody can impersonate the network.

Android phones (and probably others) let you save the network’s CA (certificate authority) on first connect, so you only need that first connection to be secure. Alternatively you can download the CA and install it manually, if you can’t even trust that first connect.

Before you say that no way will you install some random CA; no this time it’s actually fine. It’ll only be used for the WPA Enterprise networks you explicitly use it for, and not for HTTPS.

But an even better solution is to not use passwords at all, but certificates.

So here’s my walkthrough about how to enable WPA Enterprise, with certificates, on a Ubiquiti network, using FreeRADIUS running on a raspberry pi.

Architecture summary

Access points themselves can’t run a user- and certificate database. For WPA Enterprise they are just dumb agents, asking a RADIUS server who should be allowed in or who should not.

EAP-TLS is the mode you want to use. It uses the RADIUS protocol as encapsulation to let the wifi client talk directly to the RADIUS server using TLS. This TLS session uses mTLS, meaning both sides provide certificates for the other side to verify.

After the wifi client and RADIUS server has had this tunneled conversation, the AP is told to let them in.

After that the RADIUS server is no longer involved.

Configure Unifi APs for RADIUS

This is the simple part, so if you have another brand of AP, then it shouldn’t be very different, assuming it supports RADIUS.

Under Settings -> Profiles, create a new RADIUS profile for authentication.

Do not check the Enable RADIUS assigned VLAN for wired/wireless network boxes, unless you want to do more fancy things.

Under Settings -> Wireless Networks, create a new network with WPA2 Enterprise, using this RADIUS profile.

I had trouble running with PMF turned on (optional or required), which is a requirement for WPA3, so I guess I’m not running WPA3, and disabled PMF.

That’s a shame, because WPA3 has several security improvements, including mandatory protection of management frames.

Install and configure FreeRADIUS

1. apt install freeradius

Check if this is at least 3.0.26! It needs to support TLS 1.3, or certificates won’t work on modern devices. 3.0.17 (what was packaged with my Raspian based on Debian 10 (buster)) was not enough.

Username/password worked with 3.0.17, but not certificates.

There are prebuilt packages at http://packages.networkradius.com, or you can build from source.

If you installed from source then the path may be /etc/raddb/ instead of the /etc/freeradius/3.0/ that Debian uses.

2. Create CA

Edit [certificate_authority] section of /etc/freeradius/3.0/certs/ca.cnf with your details.

Bump default_days to 3650, to be valid for 10 years.

Then run make ca.pem in that directory.

3. Generate radius server certificate

This will prove to the wifi client that the access point is real.

Edit [server] in /etc/freeradius/3.0/certs/server.cnf. In particular, set the commonName to something like wifi.example.com. For example:

[server]
countryName             = GB
stateOrProvinceName     = Radius
localityName            = Somewhere
organizationName        = Example Inc.
emailAddress            = admin@example.org
commonName              = wifi.example.com

Under [req] set these:

input_password = myserverkeypassword
output_password = myserverkeypassword

The default_days doesn’t really have to be raised on the server cert. You can always regenerate the server cert without messing with all wifi clients. But you do have to regenerate the cert when it expires.

Then run make server.pem.

4. Enable clients to talk to the server

Add this to /etc/freeradius/3.0/clients.conf:

client wifi_aps {
       ipaddr = 192.168.123.0/24
       secret = radiuspasswordhere
}

5. Set FreeRADIUS cert/key

Find these keys, and set them like so, in /etc/freeradius/3.0/mods-enabled/eap:

private_key_password = myserverkeypassword
private_key_file = ${certdir}/server.key
certificate_file = ${certdir}/server.pem
ca_file = ${certdir}/ca.pem

6. Create a test user

In /etc/freeradius/3.0/users, create a test user:

bob    Cleartext-Password := "hello"

7. Restart FreeRADIUS

systemctl restart freeradius

You should now be able to connect to the wifi using:

  • EAP method: PEAP
  • Phase 2 authentication: MSCHAPV2
  • CA certificate: Either trust on first use, or import it manually.
  • Domain: wifi.example.com, per above
  • Identity: bob
  • Anonymous identity: anonymous (default)
  • Password: hello

Hopefully this worked for you. Don’t proceed until this works. But that’s not enough, we want cert based auth.

8. Generate a client cert

Edit /etc/freeradius/3.0/certs/client.cnf, setting:

  • default_days for the lifetime.
  • [client] -> commonName to identify the client.
  • [req] -> input_password and output_password with a unique password.
  • make client.pem

This also creates a client.p12, that you can load on an android phone by searching settings for Wi-Fi certificate, and adding it e.g. via Google Drive.

9. Switch to certificates

In /etc/freeradius/3.0/mods-enables/eap:

  • default_eap_type = tls
  • private_key_password
  • private_key_file
  • certificate_file
  • ca_file
  • Set use_tunneled_reply = yes everywhere the option exists in this file, and make sure it’s under the tls-config too

User login will still work, so unless you disable the other methods, that user you created will will work. So probably best to remove it from the users file.

Then restart FreeRADIUS.

10. Change wifi settings to use the cert

On Android:

  • EAP method: TLS
  • CA certificate: The CA cert you imported earlier.
  • Minimum TLS version: 1.3, to avoid getting downgrade attacks.
  • Online certificate status: Do not verify (I’ve not enabled OCSP).
  • Domain: wifi.example.com
  • Identity: Doesn’t matter, but it’ll be visible in clear text over the wire.

Your Android should now connect.

11. Connect with a Linux client

nmcli c add type wifi ifname wlan0 con-name "My-Wifi" \
      802-11-wireless.ssid "WIFI-SSID" \
      802-11-wireless-security.key-mgmt wpa-eap \
      802-1x.eap tls \
      802-1x.identity anonymous \
      802-1x.ca-cert /home/pi/CA.crt \
      802-1x.client-cert /home/pi/test.pem \
      802-1x.private-key /home/pi/test.key \
      802-1x.private-key-password testing1234

That adds a wifi with certificate auth. Then switch to this network using

nmcli c up My-Wifi

Your client is still not safe

This is all for nothing, of course, because your phone and laptop will just connect anyway to any hotel or other free wifi you’ve ever connected to in the past. An attacker can just set up a BA-Lounge wifi and wait for you to connect.

The one good thing for clients is that when they say they’re connected to “My-Wifi”, you can know that they really are connected to the real one, and not an attacker’s fake AP.

This setup does protect the network though. Users without certificates can’t connect, and can’t brute force the password.

  • https://www.titley.com/index.php/about-us/nigel/creating-self-signed-certificates-for-a-wpa-enterprise-wifi-using-freeradius/
  • https://wiki.alpinelinux.org/wiki/FreeRadius_EAP-TLS_configuration
  • https://www.tp-link.com/uk/support/faq/3456/
  • https://s55ma.radioamater.si/2020/10/28/raspberry-pi-eap-tls-wi-fi-with-nmcli-network-manager/
  • https://en.wikipedia.org/wiki/IEEE_802.11w-2009