Wireless Lan with 802.1x

Share wlan with a single mac80211 capable nic and networkmanager

Example updated to use systemd interface names that embed the PCI and/or USB bus device path in the interface names

In this example we used wlp2s0 with networkmanager to connect to an upstream wlan service. We created a wlp2s0ap with bridge ext0 interface to host a copy for clients.

Networkmanager needs to be told to ignore interfaces used to provide the accesspoint, otherwise they may be used as secondary station interfaces, although thta can also be useful to join several AndroidAP at once. Insert to /etc/NetworkManager/NetworkManager.conf to do that. I also removed references to ifupdown


Hostapd and all androidap that need to share the same station, have to all be set to use the same channel, so if one of these is an upstream we don't control, such as some remote hotspot service, then script this to set all our devices to the same channel.

We added a small delay to limit the rate at which our AP stomps on traffic from our station side, since by necessity it is all on the same channel. This has the tendency to prioritise the ap-station's own traffic over its own clients.

D-Bus can be used to dump stations from wpa-supplicant without upsetting networkmanager.

Recent NetworkManager now accepts the idea of multiple interfaces with the same MAC address, so the only residual reason is some code in linux, since we like to use the proper MAC, apart from mathematical necessity.

Allow Identical mac addresses anyway.

It is still possible with quick hack to iface.c to disable identical_mac_addr_allowed, as an unoffical modification this would taint.

  1. --- /usr/src/linux-source-4.9/net/mac80211/iface.c
  2. +++ /usr/src/linux-source-4.9/net/mac80211/iface.c
  3. @@ -305,3 +304,0 @@
  4. /home/michael/.ssh/known_hosts/home/michael/.ssh/known_hosts
  5. - if (!identical_mac_addr_allowed(iftype,
  6. - nsdata->vif.type))
  7. - return -ENOTUNIQ;
  1. make -C /usr/src/linux-headers-$(uname -r) SUBDIRS=/usr/src/linux-source-4.9/net/mac80211/
  2. modprobe -r ath5k
  3. /home/michael/.ssh/known_hosts
  4. modprobe cfg80211
  5. dpkg-divert --add --rename /lib/modules/$(uname -r)/kernel/net/mac80211/mac80211.ko
  6. ln --symbolic /usr/src/linux-source-4.9/net/mac80211/mac80211.ko /lib/modules/$(uname -r)/kernel/net/mac80211/mac80211.ko
  7. depmod -a
  8. modprobe ath5k

Why I would want do allow this

  1. iface wlp2s0ap inet manual
  2. #pre-up /sbin/iw phy phy0 interface add wlp2s0ap type __ap
  3. pre-up /sbin/iw phy phy0 interface add wlp2s0ap type managed
  4. pre-up ifconfig wlp2s0ap hw ether $(eval `cat /sys/class/ieee80211/phy0/macaddress | sed -s "s/^/printf \"%02x%s\" \\$(( 2^0x/;s/:/)) :/;"`)
  5. pre-up iwconfig wlp2s0ap retry 16 power on txpower auto
  6. pre-up sed -si "s/^channel=.*$/channel="`iwgetid -r --channel`"/" /etc/hostapd/hostapd.conf
  7. pre-up sleep 1
  8. post-down /sbin/iw dev wlp2s0ap del
  9. hostapd /etc/hostapd/hostapd.conf
  1. iface ext0 inet static
  2. pre-up sysctl net.ipv6.conf.default.forwarding=1
  3. pre-up sleep 1
  4. up tc qdisc add dev ext0 root netem delay 250ms
  5. address
  6. bridge_ports wlp2s0ap
  7. bridge_stp off
  8. bridge_ageing 0
  9. bridge_bridgeprio 34000
  10. bridge_fd 0
  11. #bridge_gcint 0
  12. bridge_hello 0
  13. bridge_maxage 0
  14. bridge_maxwait 0

IPtables NAT masquerade is then setup with wlp2s0 as the external interface and ext0 as the internal, with dhcp and possibly DNS service.


Recent editions of network manager allow the instantiation of interfaces in ad-hoc and AP mode, using functionality embedded in wpa_supplicant.

This did not have quite the same feature level as hostapd.

Other Implementatiions


UK free wlan operator www.thecloud.net used to have an Android application that enabled FastConnect, and gave an encrypted session between station and AP, a peek in settings revealed some details for creating a profile manually, on both Android and in Network Manager.

_The Cloud X
EAP method
Phase 2 authentication
PAP (MSCHAPv may also work)
Identity (when this was first seen, it was written MYCLOUD/)
mycloud/registered_e-mail for account
Anonymous Identitiy
Used the same as the Identity

Some newer Android request the Common Name and/or DNS field of server x.509 certificate, found it to be thecloud.net

Fairphone 2 and EAP

If user has a fairphone2 then it is more difficult to use connection security because wifi utility crashes when attempting to add an WPA-EAP connection, so setup a hostapd temporarily with "_The Cloud X" and user's own domain name instead of thecloud.net in "use system certificates"

The eap_user file contains an extra line

User then tests by attempting to connect to the fake AP, at least getting as far as attempting to get an IP address.

When it works, exchange for the thecloud.net, and try to connect again, which would be expected to fail, thus showing that there will be reasonably secure access when in range of a real thecloud AP.


This program creates the certificates used by FreeRADIUS and other programs.

Add object identifiers to tell Windows XP clients what the certificates are for: cat /usr/share/doc/freeradius/examples/scripts/xpextensions >> /etc/ssl/openssl.cnf

Then alter the other options in openssl.conf, especially paths for certificates in CA_default and defaults for new certiciates in req_distinguished_name

First, you probably want a root certificate if you dont already have one. This is used to sign the other certificates, so clients only need to trust it, so that trust is implied for the other certificates. I used this script from the Jabber server. It asks for a password, but the password is taken off when it is requested again.

## This generates the cert and key
## The key will be valid for 3650 days.
## Be sure to enter the FQDN of your Jabber
## server as the "Common Name".
# -x509 means make root selfsigned cert
openssl req -new -x509 -newkey rsa:1024 -days 3650 -keyout privkey.pem -out key.pem
## This will remove the passphrase
openssl rsa -in privkey.pem -out privkey.pem
## Put it all together
cat privkey.pem >> key.pem
## Cleanup
rm privkey.pem

I rename key.pem to root.pem and it goes in the /etc/ssl/certs/ directory. If other users on the system cannot be trusted, then the private key can be split off the certificate and kept in /etc/ssl/certs/private/ directory. Do remember to edit [ CA_default ] in /etc/ssl/openssl.conf to tell it where the root certificate is.

Now a server certificate for freeradius can be made, with a common root. Server certs for other SSL using things like imaps, https, jabber are made similarly.

## This generates the cert and key
## The key will be valid for 3650 days.
## Be sure to enter the FQDN of your Jabber
## server as the "Common Name".
# -x509 means make root selfsigned cert
openssl req -new -newkey rsa:1024 -days 3650 -keyout privkey.pem -out key.pem

## This will remove the passphrase
# if you bother keeping this ... it matches that specified in /etc/freeradius/eap.conf as "private_key_password ="
# however it also ask for a challenge which is what xsupplicant might ask about
openssl rsa -in privkey.pem -out privkey.pem

## Put it all together
cat privkey.pem >> key.pem

# You may need to create these files as so if this is the first cert.
#echo > /etc/ssl/index.txt
#echo 01 > /etc/ssl/serial

# -extensions read in from section in openssl.cnf
# -extensions xpclient_ext if generating for supplicant, -extensions xpserver_ext if generating for FreeRADIUS
# XP does not recognise Radius or choose its certificate otherwise.
openssl ca -extensions xpserver_ext -policy policy_anything -out signedkey.pem -infiles key.pem

cat privkey.pem >> signedkey.pem
rm privkey.pem
rm key.pem

-extensions xpserver_ext is only used when making the FreeRADIUS server certificate. It is needed for Windows XP clients to be able to use the access point.

Windows XP seems to like its certificates provided in p12 files though... In this case the passphrase has to be used to encrypt the private key, but windows lets the user remove it when this certificate/private-key is imported!


openssl req -new -keyout newreq.pem -out newreq.pem -days 3650
openssl ca -extensions xpclient_ext -policy policy_anything -out newcert.pem -infiles newreq.pem
openssl pkcs12 -export -in newcert.pem -inkey newreq.pem -out cert-clt.p12 -clcerts
openssl pkcs12 -in cert-clt.p12 -out cert-clt.pem

To complete the XP setup, the public portion of the root certificate is also imported to trust it, then Certificate authentication is set up in wireless lan settings, with My key is provided for me

Freeradius Setup

I have patched freeradius 1.5.0. We want EAP-TLS to be built.

I like to keep all my certificates together in OpenSSL, so in the tls section of eap.conf I write:

tls {
# password is not needed if the certificate does not have one
# private_key_password = cats
private_key_file = /etc/ssl/certs/radius.pem
certificate_file = /etc/ssl/certs/radius.pem
CA_file = /etc/ssl/certs/root.pem
# CA_path = /etc/ssl/certs/
dh_file = /dev/urandom
random_file = /dev/urandom
fragment_size = 1024
# include_length = yes
# check_crl = yes
check_cert_cn = %{User-Name}

Freeradius with SQL

Firstly it’s needed to give Freeradius access to an SQL database. I’m using MySQL, so to do that do like:

create database freerad;
GRANT ALL ON freerad.* TO freerad@localhost IDENTIFIED BY 'password';
use freerad;
\. /usr/share/freeradius-dialupadmin/sql/userinfo.sql
\. /usr/share/freeradius-dialupadmin/sql/badusers.sql
\. /usr/share/freeradius-dialupadmin/sql/totacct.sql
\. /usr/share/freeradius-dialupadmin/sql/mtotacct.sql
-- import the following, though it's needed to gunzip db_mysql.sql.gz and uncomment all the tables in that.
\. /usr/share/doc/freeradius/examples/db_mysql.sql.gz

The dbms login details, i.e. server, database, username, password are also specified in the /etc/freeradius/sql.conf file. Also, for security, I activate the default profile features, so usernames that are not authorised are rejected, rather than default accepting them.

default_user_profile = "DEFAULT"
query_on_not_found = yes

Add a 802.1x user (I use EAP) to a Freeradius SQL Database.

It can be tested by trying to auth the user User's Laptop. DELETE FROM radcheck; should result in the auth attempt being rejected instead. The =27 is a mime HEX-escape for a ', and they are only used to check the UserName column. Thereafter the PHP dialupadmin provided with freeradius can be used to admin which usernames are authorised to connect via 802.1x

-- Here is the first SQL that I had FreeRADIUS accepting iff a given username is mentioned in the table

DELETE FROM radcheck;
DELETE FROM radreply;
DELETE FROM usergroup;
DELETE FROM radgroupcheck;
DELETE FROM radgroupreply;

INSERT INTO radcheck (UserName, Attribute, op, Value) VALUES
        ('User=27s Laptop', 'User-Name', '==', 'User''s Laptop'),
        ('User=27s Laptop', 'Auth-Type', ':=', 'EAP');

INSERT INTO radreply (UserName, Attribute, op, Value) VALUES
        ('User=27s Laptop', 'Reply-Message', '=', 'Welcome user %u on the laptop');

INSERT INTO usergroup (UserName, GroupName) VALUES
        ('DEFAULT', 'DEFAULT');

INSERT INTO radgroupcheck (GroupName, Attribute, op, Value) VALUES
        ('DEFAULT', 'User-Name', '!=', 'DEFAULT'),
        ('DEFAULT', 'Auth-Type', ':=', 'Reject');

INSERT INTO radgroupreply (GroupName, Attribute, op, Value) VALUES
        ('DEFAULT', 'Reply-Message', '=', 'You have no account!');

Some more openssl commands

openssl x509 -inform PEM -in root.pem -outform DER -out /tmp/root.cer