Private PSK (PPSK) function on hostapd
File or RADIUS
- The PPSK function in hostapd gives the user the choice of providing the PPSKs via a file or via RADIUS.
- The option to provide the PPSKs in a text file enables fast and simplified provisioning.
FILE - Quick and dirty PPSK on OpenWrt
- We assume that you are familiar with the UCI system in OpenWrt.
- Configure an SSID with WPA2 pre-shared key.
config wifi-iface 'two' option ifname 'two0' option disabled '0' option encryption 'psk2' option isolate '0' option key '12345678' option mode 'ap' option network 'lan' option device 'radio0' option hidden '0' option ssid 'RADIUSdesk'
- Next, we will replace the key, which is a single value (12345678), with a file with multiple keys.
config wifi-iface 'two' option ifname 'two0' option disabled '0' option encryption 'psk2' option isolate '0' #option key '12345678' option wpa_psk_file /etc/psk.list option mode 'ap' option network 'lan' option device 'radio0' option hidden '0' option ssid 'RADIUSdesk'
- Here is the contents of the /etc/psk.list file
# Special MAC address 00:00:00:00:00:00 can be used to configure PSKs that # anyone can use. 00:00:00:00:00:00 highwaystar 00:00:00:00:00:00 blacknight 00:00:00:00:00:00 smokeonthewater 00:00:00:00:00:00 picturesofhome 00:00:00:00:00:00 childintime
- Restart the WiFi network
wifi down wifi up
- hostapd now goes through the list in the PSK file and checks whether it finds a match when someone tries to connect to the SSID.
FILE - Advanced PPSK on OpenWrt
- The first section dealt with a very simple PPSK implementation.
- This section is about more advanced options, including mapping MAC and VLAN to specific keys.
- You can also visit this forum discussion where most of the information comes from.
Key specific for MAC
- If we look at the comments of the sample psk.list file we see the following
# List of WPA PSKs. Each line, except for empty lines and lines starting # with #, must contain a MAC address and PSK separated with a space. # Special MAC address 00:00:00:00:00:00 can be used to configure PSKs that # anyone can use. PSK can be configured as an ASCII passphrase of 8..63 # characters or as a 256-bit hex PSK (64 hex digits). 00:11:22:33:44:55 paperplane
- The alternative 256-bit hex value is a hash that contains the specific SSID to which a user connects.
- You can generate the value using this JavaScript-based online utility from WireShark.(https://www.wireshark.org/tools/wpa-psk.html)
- When you specify a specific MAC address for a specific device, you should keep the following in mind.
- The MAC address is the MAC address of the WiFi radio that is trying to connect to the SSID and NOT the MAC address of the Ethernet interface of e.g. a laptop.
- If your phone has WiFi that supports both 2.4G and 5G, the device will usually have a radio for each frequency band and then also a MAC address for each radio.
- Also remember that there is a recent MAC randomisation feature on Android and Apple phones which can also cause the MAC address to change.
Key specific for VLAN
- If we look at the comments of the sample psk.list file also we see the following
# An optional VLAN ID can be specified by prefixing the line with # vlanid=<VLAN ID>. vlanid=3 00:00:00:00:00:00 blueforyou vlanid=4 00:00:00:00:00:00 piledriver
- A few additional steps are required for the VLAN tagging function of hostapd to work as intended.
- We need to include a few options to instruct hostapd how to handle the VLANs.
- Refer to this snippet from /etc/config/wireless
option wpa_psk_file '/etc/hostapd.wpa_psk' option vlan_file '/etc/hostapd.vlan' option vlan_tagged_interface 'eth0' option vlan_bridge 'br-vlan' option dynamic_vlan '1'
- Then here is an example of hostapd.vlan
# VLAN ID to network interface mapping 1 vlan1 2 vlan2 3 vlan3 4 vlan4 100 guest # Optional wildcard entry matching all VLAN IDs. The first # in the interface # name will be replaced with the VLAN ID. The network interfaces are created # (and removed) dynamically based on the use. * vlan#
- hostapd will create a bridge with each VLAN and automatically create tagged interfaces and make them members of this bridge:
root@OpenWrt:~# brctl show bridge name bridge id STP enabled interfaces br-vlan3 8000.4018b1eb3c80 no vlan3 eth0.3 br-lan 7fff.4018b1eb3c80 no eth0
RADIUS - PPSK on OpenWrt
- This section describes how to implement RADIUS-based PPSK on OpenWrt.
- The key to enabling RADIUS-based PPSK lies in the following setting in hostapd.conf.
# Optionally, WPA passphrase can be received from RADIUS authentication server # This requires macaddr_acl to be set to 2 (RADIUS) for wpa_psk_radius values # 1 and 2. # 0 = disabled (default) # 1 = optional; use default passphrase/psk if RADIUS server does not include # Tunnel-Password # 2 = required; reject authentication if RADIUS server does not include # Tunnel-Password # 3 = ask RADIUS server during 4-way handshake if there is no locally # configured PSK/passphrase for the STA # # The Tunnel-Password attribute in Access-Accept can contain either the # 8..63 character ASCII passphrase or a 64 hex character encoding of the PSK. # #wpa_psk_radius=0
- Option 3 was recently added and this option is a great help.
- OpenWrt generates the hostapd configuration files using the /lib/netifd/hostapd.sh script.
- This script in turn reads and interprets the /etc/config/wireless file to obtain the information needed to formulate the hostapd configuration files.
- The hostapd.sh script currently sets the wpa_psk_radius value to 2 if the ppsk '1' option is set in /etc/config/wireless.
- A better option would be to set it to 3.
- We can search for this section in hostapd.sh
if [ "$auth_type" = "psk" ] && [ "$ppsk" -ne 0 ] ; then json_get_vars auth_secret auth_port set_default auth_port 1812 json_for_each_item append_auth_server auth_server append bss_conf "macaddr_acl=2" "$N" append bss_conf "wpa_psk_radius=2" "$N" elif [ ${#key} -eq 64 ]; then
- And change it to:
if [ "$auth_type" = "psk" ] && [ "$ppsk" -ne 0 ] ; then json_get_vars auth_secret auth_port set_default auth_port 1812 json_for_each_item append_auth_server auth_server append bss_conf "macaddr_acl=2" "$N" append bss_conf "wpa_psk_radius=3" "$N" elif [ ${#key} -eq 64 ]; then
- We will look at the reason for this in the next section.
wpa_psk_radius=3
- If wpa_psk_radius=2 or wpa_psk_radius=3, the first request from hostapd to the RADIUS server looks like this:
(9) Received Access-Request Id 48 from 44.88.212.194:47297 to 164.160.89.129:1812 length 160 (9) User-Name = "ae0cd4e2c5ab" (9) User-Password = "ae0cd4e2c5ab" (9) NAS-Identifier = "m_hosta_51_74" (9) Called-Station-Id = "64-64-4A-D1-2D-69:PPSK-1" (9) NAS-Port-Type = Wireless-802.11 (9) Calling-Station-Id = "AE-0C-D4-E2-C5-AB" (9) Connect-Info = "CONNECT 11Mbps 802.11b" (9) Message-Authenticator = 0xeefd284dc6cf79df258e03b84791c2b8
- RADIUS will then typically reply with an Access Accept with the PPSK
(9) Sent Access-Accept Id 48 from 164.160.89.129:1812 to 44.88.212.194:47297 length 41 (9) Tunnel-Password := "77777777"
- The difference in behaviour between wpa_psk_radius=2 and wpa_psk_radius=3 occurs when the PPSK is not correct.
- If wpa_psk_radius=2, hostapd does NOT make any follow-up attempts.
- If wpa_psk_radius=3, hostapd makes a follow-up attempt with additional attributes:
(10) Received Access-Request Id 49 from 44.88.212.194:47297 to 164.160.89.129:1812 length 337 (10) User-Name = "ae0cd4e2c5ab" (10) User-Password = "ae0cd4e2c5ab" (10) NAS-Identifier = "m_hosta_51_74" (10) Called-Station-Id = "64-64-4A-D1-2D-69:PPSK-1" (10) NAS-Port-Type = Wireless-802.11 (10) Calling-Station-Id = "AE-0C-D4-E2-C5-AB" (10) Connect-Info = "CONNECT 11Mbps 802.11b" (10) WLAN-AKM-Suite = 1027074 (10) Attr-245.26.11344.1 = 0xc4b0e7ca5cba50304c28e6995068b4b58dfb7d82944cf9c6caba2276018debde (10) Attr-245.26.11344.2 = 0x0103007502010a0000000000000000000131a6c134eadc39dd97da1e4f9c0484e8b85d127f05edf553eb063248791ab0940000000000000000000000000000000000000000000000000000000000000000aad1fa6a0274d00e683b5947b4dc5e9d001630140100000fac040100000fac040100000fac020000 (10) Message-Authenticator = 0xd1ff97e6c9a794077c12e015e4f8e424
- RADIUSdesk then includes advanced features in FreeRADIUS to process these additional attributes and attempt to determine the user's PPSK based on hash comparisons.
- If a match is found, an access accept is returned with the plain text of the matching hash value.
(10) Sent Access-Accept Id 49 from 164.160.89.129:1812 to 44.88.212.194:47297 length 58 (10) Tunnel-Medium-Type = IEEE-802 (10) Tunnel-Type = VLAN (10) Tunnel-Private-Group-Id = "100" (10) Tunnel-Password = "11223344" (10) Finished request
- This behaviour enables PPSK in RADIUS, which does not require MAC address matching.
- To summarise once again:
- If wpa_psk_radius=2, the RADIUS implementation has to work with MAC address matching and is very cumbersome.
- If wpa_psk_radius=3, the RADIUS implementation can work with the encrypted value of the PSK specified by the user to perform a hash comparison and is therefore much more flexible. RADIUSdesk supports this option.
- However, you will need to modify the /lib/netifd/hostapd.sh file to create the hostapd configuration with this option.
Heads-Up
- Interestingly, during a troubleshooting session, I left FreeRADIUS running in debug mode for a day or two while sending requests to it from hostapd.
- At some point, it stopped receiving the follow-up request no matter how many times I restarted the access points.
- Finally, out of desperation, I restarted FreeRADIUS and lo and behold, the follow-up requests started coming in again.
- Just a heads up about FreeRADIUS.
Reference config
- Let us take a look at a simple reference configuration of /etc/config/wireless in which RADIUS-based PPSK is configured.
config wifi-iface 'zero' option ifname 'zero0' option encryption 'psk2' option acct_interval '300' option mode 'ap' option nasid 'a_hosta_53_97' option acct_server '164.160.89.129' option acct_secret 'testing123' option auth_server '164.160.89.129' option auth_secret 'testing123' option network 'lan' option device 'radio0' option ssid 'PPSK-APdesk-1' option ppsk '1' option vlan_naming '0' option vlan_tagged_interface 'wan' option vlan_bridge 'br-ex_vlan' option dynamic_vlan '1'
- RADIUS-based PPSK implementations usually consist of two components:
- The private key, which is used for authentication on the WiFi network.
- The VLAN assignment, which is usually bound to the private key specified by the user.
- The VLAN assignment is optional. If the RADIUS server has not specified a VLAN in the access acceptance, hostapd does not perform VLAN tagging for the connection of this client.
- If a VLAN is specified in the RADIUS response, the following configuration options determine how hostapd handles the VLAN assignment:
option vlan_naming '0' option vlan_tagged_interface 'wan' option vlan_bridge 'br-ex_vlan' option dynamic_vlan '1'
- If a client establishes a connection and RADIUS specifies VLAN 100, for example, hostapd dynamically creates the following bridge:
brctl show
bridge name bridge id STP enabled interfaces
br-ex_vlan100 7fff.ae7c588014f4 no vlan100
zero0.100
- The name of the bridge is formulated with the value of vlan_bridge and the appending of the VLAN number (100).
- The members of this bridge are the tagged WiFi client connection, zero0.100 and vlan100.
- The vlan100 interface requires a little more explanation. Depending on the value of vlan_naming, which can be 0 or 1, the name of the second interface is determined.
- Have a look at this part of the hostapd documentation
# When hostapd creates a VLAN interface on vlan_tagged_interfaces, it needs # to know how to name it. # 0 = vlan<XXX>, e.g., vlan1 # 1 = <vlan_tagged_interface>.<XXX>, e.g. eth0.1 #vlan_naming=0
- So if we change our configuration to the vlan_naming '1' option, the bridge would look like this:
brctl show
bridge name bridge id STP enabled interfaces
br-ex_vlan100 7fff.ae7c588014f4 no wan.100
zero0.100
- Remember that for the VLAN to work correctly, you must also provide a DHCP server in the VLAN so that the client receives an IP address after it has authenticated itself in the WiFi network.
- If you do not have such a server in your current network, you can easily do this in MESHdesk and APdesk.
- The details are explained on the corresponding wiki pages.