In a previous post I wrote about S/MIME and how to set up your own CA and create the necessary client certificates. Assuming you have now provided your users with those client certificates, you can reuse them to have password-less authentication for your WiFi. For this to work, you have to set up your WiFi access point to verify users against a RADIUS server using EAP-TLS authentication, i.e. WPA2-EAP or WPA2-Enterprise.
Before going into details on how to set this up, the general concept behind this is the following: the RADIUS server is provided with the client CA certificate. This way, it can verify the validity of any given certificate that was signed by that client CA. If a certificate is not signed by your client CA, access can be denied. If it was signed, you can use information from the certificate (e-mail, name, etc.) to decide if you want to allow access. Since only you are able to sign those client certificates, you know best what kind of information to use in order to allow or deny access. In the end, this makes passwords unnecessary.
It is crucial that you need the full control over the user base for all this to work as intended. You should not base your access policies on client certificates issued by third parties, like COMODO or StartTLS. The problem with third parties is that you do not know who really received a certificate. The third party might (rightfully) issue a certificate to someone for which your rules allow access to your WiFi; even though you do not want that person to have access!
I am using a TP-Link TL-WDR4300 running OpenWRT and will walk you through a setup like that. My goal was to have the whole access point self-contained, i.e. the router shall be able to allow WiFi access without having to query another computer (where the RADIUS server would be running on). This means, we have to set up the RADIUS server on that TP-Link box running OpenWRT.
Unfortunately, it is not as simple as installing OpenWRT, fiddling with some configuration files and be done with it. In short, we need to upgrade to FreeRADIUS 2.2.9 and downgrade to OpenSSL 1.0.1t. Long story: The reason lies in an unfortunate combination of packages provided by OpenWRT 15.05.1 for OpenSSL and FreeRADIUS and a wish of ours to utilize TLS 1.2. FreeRADIUS 2.2.6 introduced a bug in its TLS 1.2 implementation that could prevent clients from connecting. To make it more complicated, the solution has a dependency on OpenSSL as well. Here’s a quote from a post to the JISC community, which probably sums it up best:
FreeRADIUS2 < 2.2.6 should not have an issue as it doesnt DO TLS 1.2 negotiation. This may have other adverse effects with clients that try doing TLS 1.2 (we dont know, for example, what forthcoming Windows Phone releases will do) - however, 2.2.6 and 2.2.7 DO have issues - upgrade to 2.2.9 (which also has an x509 security issue fix from 2.2.8 anyway). Sites running OpenSSL 1.0.2 need 2.2.10(!)
OpenWRT 15.05.1 comes with FreeRADIUS 2.2.8 and OpenSSL 1.0.2 by default – a combination that does not really work for us. According to post, the easiest solution would be to update the OpenWRT configuration to use FreeRADIUS 2.2.10. But unfortunately, the FreeRADIUS FTP server does not provide source packages for that version. Some internet digging suggests that we are supposed to use FreeRADIUS 3 anyway, since FreeRADIUS 2.x.x will only receive security fixes … making 2.2.9 the last actual release for the foreseeable future. This leaves us with trying to compile FreeRADIUS 3 on OpenWRT or downgrading to OpenSSL 1.0.1. Hoping for OpenWRT to bring an update to FreeRADIUS 3 at some point in time anyway, I chose the (probably) less involved way of downgrading OpenSSL – until that update comes.
Compiling OpenWRT is actually rather simple, thanks to the well-written documentation and build system. You start by cloning the OpenWRT git repository:
$ git clone git://git.openwrt.org/15.05/openwrt.git
After you have followed the contained README file for installing the toolchain and downloading all package definitions, you can start modifying the Makefiles for OpenSSL and FreeRADIUS to download the versions we would like to have. Specifically, only the fields describing the version and expected MD5 checksum need to be changed.
For FreeRADIUS, navigate to feeds/packages/net/freeradius2/
to find the Makefile. Only change PKG_VERSION
and PKG_MD5SUM
:
PKG_VERSION:=2.2.9
PKG_MD5SUM:=d1398327ba4e23c75da06d8a0e01096b
For OpenSSL, you find the Makefile in package/libs/openssl/
. Here the version is specified by PKG_BASE
and PKG_BUGFIX
. Change those and the MD5 sum as follows:
PKG_BASE:=1.0.1
PKG_BUGFIX:=t
PKG_MD5SUM:=9837746fcf8a6727d46d22ca35953da1
If you are on an earlier versions of OpenWRT, you may find only PKG_VERSION
instead of PKG_BASE
and PKG_BUGFIX
.
And that’s it. You can now continue building the OpenWRT image using make menuconfig
and make
as described in the README. Remember to actually select libopenssl
and freeradius2
in menuconfig, as well as freeradius2-mod-eap
, freeradius2-mod-eap-tls
, freeradius2-mod-files
and wpad
. If you plan on enabling traditional pre-shared keys (i.e. WPA2-PSK) in addition to WPA2-EAP, also select freeradius2-mod-eap-peap
, freeradius2-mod-mschap
, and freeradius2-mod-eap-mschapv2
. After compiling and flashing (follow the guide for TP-Link WDR4300 on OpenWRT.org), you can verify the software versions after logging into LuCI.
At a minimum, you want to adapt clients.conf
and eap.conf
. The former allows control over which access points may querry this RADIUS server. Here you want to change the secret
to be better than the default of “testing123.” The second configuration file, eap.conf
, requires a few more changes. Starting at the beginning, the eap
sections contains the field default_eap_type
which should be tls
. Further down you will find a sub-section named eap
. Set private_key_file
and certificate_file
to the private key and public certificate of the server certificate for the RADIUS server. To avoid problems of missing intermediate certificates, make sure the public certificate contains the whole certificate chain up to the root certificate your end devices will trust. CA_file
should point to the CA certificate that signs the certificates of your end devices, i.e. the client CA certificate.
Now that you have the certificate part set up, you may also want to change the cipher_list
from DEFAULT
to something more specific (get a full list by running openssl ciphers
). For example, if you want perfect forward secrecy, select ciphers that use an ephemeral key exchange algorithm, i.e. those starting with DHE or ECDHE. If you are not sure what that means, there is a nice blog article by Vincent Bernat on this. You could also further restrict the allowed encryptions algorithms to only use a form of AES and/or restrict the MAC algorithms to SHA-2. Though, be aware that at some point you will shut out some devices. The following rather restrictive cipher list worked for me with any device I wanted to connect so far:
cipher_list = "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA"
Additionally, I set check_cert_cn = %{User-Name}
to tie the login name to the name specified in the given certificate. If they do not match, the connection attempt will fail.
Last but not least, you have to define the users that are actually granted access. At a mininum, the users
file could look like the following:
"Jakob Bieling" Auth-type := EAP
DEFAULT Auth-type := Reject
Reply-Message := "Access denied."
This will allow access if a certificate issued for Jakob Bieling is used, and reject all others.
Setting up OpenWRT to actually authenticate users against the RADIUS server is pretty straightforward. Assuming you have installed the configuration interface LuCI and already set up a wireless network, open the settings for that WiFi network. In the section Interface Configuration you will find a tab Wireless Security, where you are able to select WPA2-EAP from a list of encryption methods (first item). The items below will now update and almost every one of them has Radius in its name. Enter 127.0.0.1
into the text fields labelled Server. Leave the ports at their defaults. The Radius-Authentication-Secret is the one you specified above for the secret
. Now Save & Apply those changes.
So far, you only read about simply reusing S/MIME certificates to authenticate against a WiFi access point. What if you want WiFi access for a device that 1) does not have an associated e-mail and 2) you don’t want to use the S/MIME certificate of one specific person? Instead of creating a certificate for a dummy e-mail address, you are also able to create a client certificate that is not bound to an e-mail address. On the one hand, this certificate cannot be used for signing or encrypting e-mails. But on the other hand, it can be used to authenticate against the WiFi access point!
Using the Bash script introduced in the previous post, there are also configuration files available for this already, which work with the client CA. Assuming you already have a client CA, creating and signing the client certificate should use the client-authonly
configuration:
$ createClientKey myCertName client-authonly
$ signCertificate myCertName client-authonly