Using a RADIUS 3.X Server on Ubuntu 14.04 for WIFI Authentication

Using a RADIUS 3.X Server on Ubuntu 14.04 for WIFI Authentication

This is an update from an older article on Freeradius 2.x. This version covers Freeradius 3.x

Looking for how to add a CRL? See my new article on that.

Thanks to TechTalk for their help in debugging this article.

Let's be honest. Your wifi password is probably something pretty simple. When you have to be able to both verbally convey the password to new users and type it in on a mobile device, it's not like the password can be 25 random characters including special characters, can it?

To have real security, you should be using a pre-shared encryption certificate. This moves the security from "something you know", aka your password, to "something you have", an encryption certificate file. Most modern Wireless Access Points (WAP) support WPA2-Enterprise which expects that you are running a RADIUS server for authenticating clients.

Now there's many ways that a RADIUS server can be configured but I'm going to suggest one that generates signed certificates for users that then must be installed on their devices. Other RADIUS implementations allow you to store a unique user login in an LDAP database backend for instance, but rather than providing attackers a huge list of possible passwords to crack we want to eliminate the password as a possible login method entirely.

RADIUS is an acronym for "Remote Authentication Dial In User Service." You may be able to tell by the name that it's not a new technology - the last time I used a dial-in connection was probably 16 years ago. Fortunately for us this means that RADIUS is a well established and tested standard and because it's also flexible, we can now use it for authenticating users in many different scenarios, including WIFI.

A few pre-requisites I'm going to assume

I'm going to assume that you have a WAP that supports WPA2-Enterprise.

Your WAP must be configured with a static IP address.

You also need a server with a static IP address running Ubuntu 14.04 that you intend to run a RADIUS server on.

You have a basic knowledge of administering Linux and Ubuntu servers already.

Install FreeRADIUS 3.x From The PPA Repository

For this it will be much easier if you just run the following on the server that will host Freeradius...

sudo su -

...and become the root user.

First, let's add the PPA repository for the Freeradius 3.x stable branch:

apt-get install python-software-properties
apt-add-repository ppa:freeradius/stable-3.0
apt-get update
apt-get install freeradius make

There are many different ways that FreeRADIUS can be configured, and honestly I don't understand most of them. Here's what I found that worked for me.

Turn off the proxy feature on the server (unless you know you need it) by editing /etc/freeradius/radiusd.conf and changing the following line:

proxy_requests = no
# $INCLUDE proxy.conf

You may also want to look over the logging features in that configuration file to set what gets logged and where. I use "auth=yes" in the log{} block so that I log every time someone connects to the wifi. It also tells me which access point they connected to.

What is a Radius client?

FreeRADIUS may throw you for a loop talking about servers and clients. The client is NOT what you think - it's not the user's laptop or phone. The client is the WAP, because it performs the authentication request against the server. This confusion is exacerbated by the fact that to configure a user certificate, you edit a file called "client.cnf".

By default, FreeRADIUS will set up the localhost of the server as a client as well, and we won't be needing that so let's just start a new clients.cnf file and put our entry for our WAP in that. Create a new random password that you'll enter into the WAP itself that it uses to authenticate against the RADIUS server. Again in the '/etc/freeradius/clients.conf' file:

# -*- text -*-
##
## clients.conf -- client configuration directives
##
##      $Id$

#######################################################################
#
#  Define RADIUS clients (usually a NAS, Access Point, etc.).

client mywap {
        ipaddr = 192.168.1.100
        secret = myRandomP@55w05D
        require_message_authenticator = yes
}

Please be sure you've changed the ipaddr and secret lines. You will need a client entry for each WAP that is on your network. The client name is arbitrary, but will show in the logs when a user authenticates, so it's always good to be able to easily identify which WAP a user connected to. I recommend a different password for each one, in addition to needing the static IP address of the WAP.

When you configure the "WPA2-Enterprise" options on your WAP, you'll enter the IP address of your Radius server, and this password.

EAP Configuration

Next we want to edit the configuration for the Extensible Authentication Protocol (EAP). Rather than telling you what to comment, I'm going to just show you what you need. Edit '/etc/freeradius/mods-available/eap' to look something like this:

# -*- text -*-
# Example /etc/freeradius/mods-available/eap file
eap {
        default_eap_type = tls
        timer_expire = 60
        ignore_unknown_eap_types = no
        cisco_accounting_username_bug = no
        max_sessions = 4096
        tls {
                certdir = ${confdir}/certs
                cadir = ${confdir}/certs
                private_key_password = myserverkeypassword
                private_key_file = ${certdir}/server.key
                certificate_file = ${certdir}/server.pem
                ca_path = ${cadir}
                ca_file = ${cadir}/ca.pem
                dh_file = ${certdir}/dh
                random_file = /dev/urandom
                cipher_list = "HIGH"
                make_cert_command = "${certdir}/bootstrap"
                ecdh_curve = "prime256v1"
                cache {
                        enable = no # Optionally enable
                        lifetime = 24 # hours
                        max_entries = 255
                }
                verify {
                        tmpdir = /tmp/radiusd
                        client = "/usr/bin/openssl verify -CAfile ${..ca_file} %{TLS-Client-Cert-Filename}"
                }
                ocsp {
                        enable = no # optionally enable
                        override_cert_url = yes
                        url = "http://127.0.0.1/ocsp/"
                }
        }
        ttls {
                default_eap_type = md5
                copy_request_to_tunnel = no
                use_tunneled_reply = no
                virtual_server = "inner-tunnel"
        }
}

The "myserverkeypassword" above will need to match the password you use when generating the server's keys later.

What we've done mostly is disable other protocols like LEAP and PEAP and MSCHAPv2 among others, none of which are good ideas to use. Only EAP-TLS will be used.

Disable all the default servers

rm /etc/freeradius/sites-enabled/*

Create a new server config file at /etc/freeradius/sites-available/mynetwork that contains something like the following:

######################################################################
server {
	listen {
		type = auth
		port = 1812
		ipaddr = *
	}
	authorize {
		preprocess
		eap {
		        ok = return
		}
		expiration
		logintime
	}
	authenticate {
		eap
	}
	preacct {
		preprocess
		acct_unique
		suffix
		files
	}
	accounting {
		detail
		# unix
		radutmp
		# exec
		attr_filter.accounting_response
	}
	session {
		radutmp
	}
	post-auth {
		# exec
		Post-Auth-Type REJECT {
		        attr_filter.access_reject
		}
	}
	pre-proxy {

	}
	post-proxy {
		eap
	}
}

Now, link that to the sites-enabled directory like so:

cd /etc/freeradius/sites-enabled/
ln -s ../sites-available/mynetwork ./mynetwork

Configure SSL Certificates

Assuming all went well, now we start generating SSL certificates. First we want to remove the default certificates and set up a basic framework:

cd /etc/freeradius/certs
rm *
cp /usr/share/doc/freeradius/examples/certs/* /etc/freeradius/certs/

Now we want to edit the /etc/freeradius/certs/ca.cnf file and change the following options:

[CA_default]
..
default_days = 1825
..
[req]
default_bits = 4096
input_password = mycapassword
output_password = mycapassword
..
[certificate_authority]

Edit the lines under the certificate_authority section to match what your certificate should say about you, and change the CA password that's in bold above.

Now we make the CA keys and the DH file:

make ca.pem
make ca.der
make printca
make dh

And now we edit the server.cnf file making some similar changes:

[ CA_default ]
..
default_days = 1825
..
[ req ]
..
default_bits = 4096
input_password = myserverkeypassword
output_password = myserverkeypassword

[server]

Change the server section to match what your certificate should say about your server. Note that the passwords in this file should match the password in the eap file we configured previously. Now make the server certificate:

make server.pem

Last bit of server configuration

Freeradius 3.x doesn't appear capable of creating it's temp directory, so I had to do this by hand:

mkdir /tmp/radiusd
chown freerad:freerad /tmp/radiusd
chmod 700 /tmp/radiusd

Let's test the server

We should be ready to launch the server now, so let's run it in the foreground first to make sure everything launches correctly:

service freeradius stop
freeradius -X

The last line should say: "Ready to process requests"

If the test all goes well you can stop the server with: ctrl-c

Create user certificates

Now we generate client certificates, but there's something we need to change in the Makefile first. "nano Makefile".

Locate the lines that say:

client.p12: client.crt
  openssl pkcs12 -export -in client.crt -inkey client.key -out client.p12  -passin pass:$(PASSWORD_CLIENT) -passout pass:$(PASSWORD_CLIENT)

client.pem: client.p12
  openssl pkcs12 -in client.p12 -out client.pem -passin pass:$(PASSWORD_CLIENT) -passout pass:$(PASSWORD_CLIENT)
  cp client.pem $(USER_NAME).pem

Change it to read:

client.p12: client.crt
	openssl pkcs12 -export -in client.crt -inkey client.key -out client.p12  -passin pass:$(PASSWORD_CLIENT) -passout pass:$(PASSWORD_CLIENT)
	cp client.p12 $(USER_NAME).p12

client.pem: client.p12
	openssl pkcs12 -in client.p12 -out client.pem -passin pass:$(PASSWORD_CLIENT) -passout pass:$(PASSWORD_CLIENT)
	cp client.pem $(USER_NAME).pem

client_android.p12: client.crt
	openssl pkcs12 -export -in client.crt -inkey client.key -certfile ca.pem -name "$(USER_NAME)" -out client_android.p12  -passin pass:$(PASSWORD_CLIENT) -passout pass:$(PASSWORD_CLIENT)
	cp client_android.p12 $(USER_NAME)_android.p12

Make sure indented lines are tabs and not spaces or the file will not work. If you just copy-paste this, it will probably paste as spaces, and you'll need to delete the indents and replace with tabs. It's a Makefile thing. These edits create a special case for Android certificates and renames the files to be easier to identify.

nano client.cnf

Edit 'client.cnf' to set your defaults just like you did before but this time for any client certificates. You probably want to change the default_days to 365 (will need to regenerate keys for the device in a year) but again change the default_bits to 4096.

In the "[ req ]" section of client.cnf is the "input_password" and "output_password". Set these both to the same, and keep in mind that this password will be needed when the certificate is installed on the client so keep in mind using mobile keyboards to type it as you choose the password.

[ CA_default ]
..
default_days = 365
..
[ req ]
prompt = now
distinguished_name = client
default_bits = 4096
input_password = clientpassword
output_password = clientpassword
..

Note that the "distinguished_name" should remain as "client" and not the name of the client.

The "[client]" section uniquely identifies the user in log files, so be sure the emailAddress and commonName are set properly to the user's email address. It causes less confusion if the emailAddress and commonName bothd match.

Now create the client certificate with:

make client.pem
make client_android.p12

Simply edit the client.cnf file for the next certificate and run those commands again to generate certificates for each device that will have WIFI access.

Finally, lets set the proper permissions for certificates:

chmod 600 *
chown root:freerad *
chmod 640 ca.pem
chmod 644 dh
chmod 640 server.key
chmod 640 server.pem

The Right Certificates in the Right Places

Here's the files needed:

Note that recent versions of Android will constantly display a warning that your connection is monitored while using wifi with a RADIUS server. There are ways on a rooted device to install the certificate in the root store, but it doesn't actually affect the operation of the device.

Should be ready to go

You should have everything configured at this point and be able to launch your Freeradius server with:

service freeradius restart

If you run into any trouble, launch it in the foreground by running:

freeradius -X

This will give you more debug output and show what's happening when a client authentication request arrives.

Posted by Tony on Feb 16, 2016 | Servers, Network Security, Freeradius