18 mars 2009

Howto setup an EAP-TLS WPA network with freeradius

A WPA entreprise network secured with EAP/TLS & Freeradius


The most important choice to make when implementing WPA entreprise is which flavor of EAP to use. This choice is mainly limited by your client platform. Indeed, the freeradius server licensed under the free GPL license could be made compliant with virtually all EAP method you may dream of. Your wireless access point is EAP agnostic. You only have to verify that it supports WPA entreprise sometimes mentioned as 802.1x by some vendors. It simply passes EAP traffic from clients to servers, without requiring explicit support for any particular EAP subtype.
What your client platform supports is a function both of your client operating system and of its wireless hardware. For example, a Microsoft Windows XP system with an Centrino chipset supports EAP-TLS and PEAP, but EAP-TTLS isn't an easy option if using a Microsoft OS. At the opposite if you run Linux with wpa_supplicant, you have a much wider range of choices available.

Here we choose to use EAP-TLS. EAP-TLS requires client certificates, which in turn requires you to set up a certificate authority (CA). TLS authentication provides strong security thanks to X.509 certificate. In fact it doesn't require that much work to use OpenSSL to create your own CA.

In this howto, Windows XP clients use EAP-TLS to connect to a WPA-enabled access point. The access point, in turn, is configured to authenticate on a FreeRADIUS server running Linux (Debian Lenny).

Freeradius with EAP-TLS/TTLS/PEAP support

Debian's freeRadius package is built without support for EAP/TLS/TTLS/PEAP because of the licensing problems of the OpenSSL library. We want to implement 802.1x network authentication with strong security, so we need it. We will build Debian package (lenny, stable at time of writing 10 March 2009) linked to libssl and with EAP/TLS/TTLS/PEAP support compiled in.

I suppose you made a minimal installation of lenny and you added a minimal gnome environment.

$ apt-get install x-window-system-core
$ apt-get install gnome-core synaptic

Then in order to build the missing packages you need to install dpkg-dev and fakeroot (to limit root access)

$ apt-get install dpkg-dev fakeroot

Download the newest source package (orig.tar.gz), Debian diffs (diff.gz) and description file (dsc) from the freeradius package page. The version I tested the procedure with is freeradius-2.0.4+dfsg

Unpack the source and switch to the resulting directory like this:

# dpkg-source -x *.dsc
dpkg-source: extracting freeradius in freeradius-2.0.4+dfsg
dpkg-source: unpacking freeradius_2.0.4+dfsg-6.diff.gz
dpkg-source: applying ./freeradius_2.0.4+dfsg-6.diff.gz
# cd freeradius-*

There are two files that must be edited in order to successfully build the package:

1. Edit debian/rules, search for eap and change every mentioning of --without-rlm_eap-* to --with-rlm_eap-* excepted --without-rlm_eap_ikev2, --without-rlm_eap_tnc --without-rlm_sql_oracle --without-rlm_sql_unixodbc --without-rlm_otp
A few lines below, in the same file, replace --without-openssl with --with-openssl.

So it should look like:

--with-rlm_eap_tls \
--with-rlm_eap_ttls \
--with-rlm_eap_peap \
--without-rlm_eap_tnc \
--without-rlm_otp \
--with-rlm_sql_postgresql_lib_dir=`pg_config --libdir`\
--with-rlm_sql_postgresql_include_dir=`pg_config --includedir` \
--with-openssl \
--without-rlm_eap_ikev2 \
--without-rlm_sql_oracle \
--without-rlm_sql_unixodbc \

Still editing the same file, find the following code and comment it entirely:

for pkg in ${pkgs} ; do \
if dh_shlibdeps -p $$pkg -- -O 2>/dev/null | grep -q libssl; then \
echo "$$pkg links to openssl" ;\
exit 1 ;\
fi ;\

2. Finally, edit debian/control and at the end of the line starting with Build-Depends: add , libssl-dev

Finally, I needed to install some packages before running "dpkg-buildpackage -rfakeroot":

# apt-get install libssl-dev debhelper libgdbm-dev libiodbc2-dev libkrb5-dev libldap2-dev libltdl3-dev libmysqlclient15-dev libpam0g-dev libpcap-dev libperl-dev libpq-dev libsasl2-dev libsnmp-dev python-dev

You can now build new packages with EAP/TLS/TTLS/PEAP support like this:

# dpkg-buildpackage -rfakeroot

If everything goes well, you'll find 10 debian packages in the parent directory which you can now install. Don't forget to hold newly installed packages in your package manager. Otherwise new official versions (without EAP/TLS/TTLS/PEAP support) should overwrite your custom built packages when upgrading.

A way to achieve the "hold" is by using dpkg

Put a package on hold
echo “package hold” | dpkg --set-selections
echo “freeradius hold” | dpkg --set-selections
Remove the hold
echo “package install” | dpkg --set-selections
echo “freeradius install” | dpkg --set-selections
Knowing the status of your packages
dpkg --set-selections

Now I show you what's happening when installing the newly created packages on a frenchspeaking lenny server (hostname: hp-debian-stable.multitel.be)

hp-debian-stable:/home/hanoteau# dpkg --install freeradius-common_2.0.4+dfsg-6_all.deb
Sélection du paquet freeradius-common précédemment désélectionné.
(Lecture de la base de données... 99926 fichiers et répertoires déjà installés.)
Dépaquetage de freeradius-common (à partir de freeradius-common_2.0.4+dfsg-6_all.deb) ...
Paramétrage de freeradius-common (2.0.4+dfsg-6) ...
Ajout de l'utilisateur freerad au groupe shadow
Traitement des actions différées (« triggers ») pour « man-db »...

hp-debian-stable:/home/hanoteau# dpkg --install libfreeradius2_2.0.4+dfsg-6_i386.deb
Sélection du paquet libfreeradius2 précédemment désélectionné.
(Lecture de la base de données... 100311 fichiers et répertoires déjà installés.)
Dépaquetage de libfreeradius2 (à partir de libfreeradius2_2.0.4+dfsg-6_i386.deb) ...
Paramétrage de libfreeradius2 (2.0.4+dfsg-6) ...

hp-debian-stable:/home/hanoteau# dpkg --install freeradius_2.0.4+dfsg-6_i386.deb
(Lecture de la base de données... 100317 fichiers et répertoires déjà installés.)
Préparation du remplacement de freeradius 2.0.4+dfsg-6 (en utilisant freeradius_2.0.4+dfsg-6_i386.deb) ...
Dépaquetage de la mise à jour de freeradius ...
Paramétrage de freeradius (2.0.4+dfsg-6) ...
suppression du / final
suppression du / final
suppression du / final
Starting FreeRADIUS daemon: freeradius.

Now Freeradius is supposed to run, let's go further

Creating a Certificate Authority

Before we configure FreeRADIUS, we need to create some certificates. And before we create any certificates, we must create our CA.
A CA is a system that acts as the root of a public key infrastructure. It's the central authority that guarantees, by way of digital signatures, the authenticity of all certificates issued in your organization. It also periodically issues certificate revocation lists (CRLs), lists of certificates the CA no longer guarantees, for example, certificates issued to people who've left the organization, servers that are no longer on-line and so on.
None of this requires your CA to act as an actual server; in fact, it's better if it doesn't. For a CA to be trustworthy, it must be protected carefully from misuse. So your CA should be on a not permanently connected server or on a virtual machine.I recommend you virtual box OSE for freely creating virtual machines.
If you already have a CA that you've used to create certificates for Web servers or other applications that use TLS then just use it for WPA too. If not, here's how to create a CA. First, make sure your designated CA system has OpenSSL installed. OpenSSL is a standard package on all popular Linux distributions, not to mention BSD. One quick way to make sure you have OpenSSL is to issue the command which openssl. This command returns the path to your OpenSSL command, if it's installed.

On debian Lenny the path is: /usr/bin/openssl

Next, change your working directory to wherever your system keeps OpenSSL's configuration and certificate files. On debian lenny, this is /etc/ssl.
Now, open the file openssl.cnf with your text editor of choice, do you know vim? We will tweak some default settings so as to make certificate creation speedier later on. Feel free to adapt this to your special needs or go to the next step if you are in a hurry.

Changes to openssl.cnf for Optimal Certificate Creation

# First we change the CA root path in the CA_default
# section to reflect the CA we're about to create

[ CA_default ]
dir = ./jhCA # Where everything is kept by default ./demoCA

# The following lines are further down in openssl.cnf:

countryName_default = Be
stateOrProvinceName_default = Hainaut
0.organizationName_default = Multitel ASBL

Next, we should edit the CA creation script to change our CA's root directory to something other than demoCA, that is, to match the dir variable we just changed in openssl.cnf. I use the script CA.sh, which on Debian lenny systems is located in /usr/share/ssl/misc. The line you need to change is CATOP=./jhCA.

If you changed your working directory to edit this file, change back to your SSL configuration directory, for example, /etc/ssl. From there, run the CA.sh script with the -newca option, for example, /usr/lib/ssl/misc/CA.sh -newca. You then are prompted to create a new root certificate and to type a passphrase for its private key. Choose a difficult-to-guess passphrase, and write it down in a safe place—if you forget it, you'll be unable to use your CA.

If you really want to follow this howto witout needing any personal input feel free to type the proposed password. Doing so you will have an unsecure EAP-TLS test infrastructure.

passphrase: strongpasswordbebete
challenge password: telematique

After the script is done, your SSL configuration directory should contain a new directory, jhCA in our example. At the root level of this directory is your new CA's public certificate; by default this file is named cacert.pem. You need to copy this file to your FreeRADIUS server and to each wireless client.
There's one more thing you need to do before creating certificates if you've got Windows XP wireless clients. Windows XP expects certain attributes in server and client certificates, so you need to create a file called xpextensions that contains the lines shown below.

Contents of xpextensions



It should be in the same directory as openssl.cnf.

In EAP-TLS, a wireless client and your RADIUS server mutually authenticate each other. They present each other with their respective certificates and cryptographically verify that those certificates were signed by your organization's certificate authority. In some ways, this is an elegant and simple way to handle authentication. After you install the CA's public certificate on the FreeRADIUS server, you don't need to configure any other client information explicitly, such as user names, passwords and so on.
That doesn't mean EAP-TLS is less work than user name-password schemes, however. You still need to use OpenSSL to create certificates for all your users and copy those certificates over to them. You also need to ensure that everyone has a copy of the root CA certificate installed in the proper place.

Creating Certificates

For EAP-TLS, you need at least two certificates in addition to your CA certificate, a server certificate for your FreeRADIUS server and one client certificate for each wireless client on your network. Creating certificates is a three-step process:

Generate a signing request, that is, an unsigned certificate.
Sign the signing request with your CA key.
Copy the signed certificate to the host on which it will be used.

Let's start by creating a server certificate signing request using OpenSSL's req command:

$ openssl req -new -nodes -keyout server_key.pem -out server_req.pem -days 730 -config ./openssl.cnf
(challenge password : telematique)

This command creates the files server_req.pem, which contains the actual request—an unsigned certificate—and server_key.pem, its passphrase-less private key. First, though, you are prompted for your organization's Country Code, State and so on, much of which can use the default values defined in openssl.conf. Pay special attention, however, to Common Name. When prompted for this, type the fully qualified domain name of your server, for example, hp-debian-stable.multitel.be.

Next, let's use our CA key to sign the request by using OpenSSL's ca command:

$ openssl ca -config ./openssl.cnf \
-policy policy_anything -out server_cert.pem \
-extensions xpserver_ext -extfile ./xpextensions \
-infiles ./server_req.pem


This command reads the file server_req.pem and, after prompting for your CA key's passphrase, saves a signed version of it plus its corresponding private key to the file server_cert.pem. Notice the -extensions and -extfile options—this is why earlier we created the file xpextensions.
Open your signed certificate with the text editor of your choice and delete everything before the line -----BEGIN CERTIFICATE-----. Concatenate it and your key into a single file, like this:

$ cp server_cert.pem server_cert.pem-backup

$ cat server_key.pem server_cert.pem > \


Now we've got a server certificate with a key that we can copy over to our FreeRADIUS server. Its private key isn't password-protected, however, so be sure to delete any extraneous copies after you've got it in place.

Now we need to create a client certificate signing request. The OpenSSL command to do this is similar to that used to create server certificates:

$ openssl req -new -keyout client_key.pem \
-out client_req.pem -days 730 -config ./openssl.cnf

As you can see, we're writing our signing request and key to the files client_req.pem and client_key, respectively. Unlike with the server signing requests, however, we're omitting the -nodes option. Therefore, when you run this command, you are prompted for a passphrase with which the certificate's private key can be encrypted.
Enter PEM pass phrase: devil1

Next we sign the client certificate's signing request:

$ openssl ca -config ./openssl.cnf \
-policy policy_anything -out client_cert.pem \
-extensions xpclient_ext -extfile ./xpextensions \
-infiles ./client_req.pem

(challenge password : telematique1)

Again, this is similar to the equivalent command for our server, except this time the -extensions command references a different entry in xpextensions. Also, if your clients run Linux, you should delete the extraneous stuff in the certificate, like you did with server_cert.pem. You then either can leave the certificate and key files separate or concatenate them. From there, copy your client certificate file(s) to your Linux client system.

If your certificate is to be used by a Windows XP client, you have one more step to take. You need to convert the certificate file(s) to a PKCS12-format file, with this command:

$ openssl pkcs12 -export -in client_cert.pem \
-inkey client_key.pem -out client_cert.p12 -clcerts

(enter passphrase for ./jhCA/private/cakey.pem devil1)

You are prompted for client_key.pem's passphrase and then for a new passphrase for the new file; you can use the same password as before if you like. You may be tempted simply to press Enter instead, especially given that the WPA supplicant in Windows XP works only when you store its certificates without passphrases. It could be dangerous to move private keys around networks unprotected, so It would be good practice if you remove the passphrase after this file is copied safely over to your Windows XP client.

The resulting file, in this example client_cert.p12, contains both your signed certificate and its private key. Copy it to your Windows XP client system.

So we have generated server and client certificates and transferred them to their respective hosts. Now we need to configure FreeRADIUS, our access point and our wireless clients.

The tasks at hand are:

To install the server and CA certificates we created last time onto our FreeRADIUS server.
To configure FreeRADIUS to use these certificates with EAP-TLS to authenticate users for our access point.
To configure our access point to redirect authentication to our FreeRADIUS server.
To install the client and CA certificates we created last time onto a Windows XP client and configure it to use WPA when connecting to the WLAN.

Configuring the freeradius server

We created three X.509 digital certificates: a certificate authority certificate, called cacert.pem; one server certificate, called server_keycert.pem; and a client certificate, called client_cert.p12. The server and client files contain both a certificate and its private key, so each of these must be handled carefully. The CA certificate, however, is stored separately from its key, so you can distribute cacert.pem freely.
FreeRADIUS stores its configuration files in /etc/freeradius/ in Debian lenny. This directory contains a subdirectory, certs/—this, naturally, is where you need to copy your CA certificate and your server certificate/key. Make sure that cacert.pem is owned by the user root and that its permissions are set to -r--r--r--.
server_keycert.pem, on the other hand, should be owned by the user freerad and its permissions set to -r--------.

cp /etc/ssl/jhCA/cacert.pem /etc/freeradius/certs/cacert.pem
cp /etc/ssl/server_keycert.pem /etc/freeradius/certs/server_keycert.pem

Hereafter, the listing shows the long directory listings for these two files.

-r--r--r-- 1 root freerad 1294 2009-02-10 01:05 cacert.pem
-r-------- 1 freerad freerad 1894 2009-02-10 01:00 server_keycert.pem

You also should make sure that the file /var/log/freeradius/radius.log and the directory /var/run/freeradius/ are writable by freerad. Both radius.log and freeradius/ may be owned by freerad.

Before we edit freeradius' configuration files, we need to create two files that freeradius must have in order to use TLS. The first is a Diffie-Hellman parameters file, or dh file, which is used for negotiating TLS session keys. To create a dh file, change your working directory to /etc/freeradius/certs/ directory and issue this command:

# openssl dhparam -check -text -5 512 -out dh

The second file you need is a data file that contains a random bitstream that also is used in TLS operations. From within certs, run this command:

# dd if=/dev/urandom of=random count=2

Both of these files need to be readable by the user freerad, but they should not be writable by anybody.

# chown freerad dh
# chmod o-w dh

We're finally ready to configure freeradius. You may be afraid when you see the long list of files in /etc/freeradius, but don't be. For WPA with EAP-TLS, we need to edit only three files: radiusd.conf, eap.conf and clients.conf.

In radiusd.conf, all we need to do is verify the user and group accounts that the radiusd process runs as. By default these are inherited from whatever user starts the dæmon. If you run radiusd from a startup script, this is root; however, you definitely do not want to run radiusd as root. Therefore, you should set the user and group parameters in radiusd.conf, both set to freerad, as shown below.

Two Parameters to verify in radiusd.conf

user = freerad
group = freerad

Naturally you can choose different nonprivileged user and group accounts instead of freerad and freerad, but if you do so, you need to adjust the ownerships and permissions on the certificate files we created earlier. Regardless, make sure your nonprivileged user's entry in /etc/password sets the user's shell to a non-shell, such as /bin/false or /bin/true—this account should not be usable for SSH, telnet or similar programs. For that matter, make sure both the user and group accounts exist in the first place, and create them if they don't.
Other parameters may be set in radiusd.conf, but these really are the most important parameters we have to check.

The next file we need to edit is eap.conf; here's where the real heavy lifting occurs. Listing below shows the lines you need to edit in eap.conf.

Changes in eap.conf

eap {
# There are several generic EAP parameters you can
# set here, but the important one for our purposes
# is default_eap_type:

default_eap_type = tls

# Next come parameters for specific EAP types. Since
# we're going to use EAP-TLS, the tls{} section is
# the one we care about:

tls {
# These is used to simplify later configurations.
certdir = ${confdir}/certs
cadir = ${confdir}/certs
private_key_password = whatever
private_key_file = ${certdir}/server_keycert.pem

# If Private key & Certificate are located in
# the same file, then private_key_file &
# certificate_file must contain the same file
# name.
# If CA_file (below) is not used, then the
# certificate_file below MUST include not
# only the server certificate, but ALSO all
# of the CA certificates used to sign the
# server certificate.
certificate_file = ${certdir}/server_keycert.pem

# Trusted Root CA list
# ALL of the CA's in this list will be trusted
# to issue client certificates for authentication.
# In general, you should use self-signed
# certificates for 802.1x (EAP) authentication.
# In that case, this CA file should contain
# *one* CA certificate.
# This parameter is used only for EAP-TLS,
# when you issue client certificates. If you do
# not use client certificates, and you do not want
# to permit EAP-TLS authentication, then delete
# this configuration item.
CA_file = ${cadir}/cacert.pem

# For DH cipher suites to work, you have to
# run OpenSSL to create the DH file first:
# openssl dhparam -out certs/dh 1024
dh_file = ${certdir}/dh
random_file = ${certdir}/random

# This can never exceed the size of a RADIUS
# packet (4096 bytes), and is preferably half
# that, to accomodate other attributes in
# RADIUS packet. On most APs the MAX packet
# length is configured between 1500 - 1600
# In these cases, fragment size should be
# 1024 or less.
fragment_size = 1024

# include_length is a flag which is
# by default set to yes If set to
# yes, Total Length of the message is
# included in EVERY packet we send.
# If set to no, Total Length of the
# message is included ONLY in the
# First packet of a fragment series.
include_length = yes

# Check the Certificate Revocation List
# 1) Copy CA certificates and CRLs to same directory.
# 2) Execute 'c_rehash '.
# 'c_rehash' is OpenSSL's command.
# 3) uncomment the line below.
# 5) Restart radiusd
# check_crl = yes
# CA_path = /path/to/directory/with/ca_certs/and/crls/

# If check_cert_issuer is set, the value will
# be checked against the DN of the issuer in
# the client certificate. If the values do not
# match, the cerficate verification will fail,
# rejecting the user.
# check_cert_issuer = "/C=GB/ST=Berkshire/L=Newbury/O=My Company Ltd"

# If check_cert_cn is set, the value will
# be xlat'ed and checked against the CN
# in the client certificate. If the values
# do not match, the certificate verification
# will fail rejecting the user.
# This check is done only if the previous
# "check_cert_issuer" is not set, or if
# the check succeeds.
check_cert_cn = %{User-Name}
# Set this option to specify the allowed
# TLS cipher suites. The format is listed
# in "man 1 ciphers".
cipher_list = "DEFAULT"


# This configuration entry should be deleted
# once the server is running in a normal
# configuration. It is here ONLY to make
# initial deployments easier
# make_cert_command = "${certdir}/bootstrap"


We have specified a server-key passphrase with the private_key_password parameter. This actually should be empty if you created your server certificate and key with OpenSSL's -nodes option.
Make sure that eap.conf is owned and readable only by root . This may seem paradoxical doesn't freerad need to be able to read configuration files? But, if you start the freeradius daemon as root, it reads its configuration files, including radiusd.conf, eap.conf and clients.conf, before demoting itself to freerad.
Finally, you need to create an entry for your access point in clients.conf. The listing below shows such an entry for a 3com 7760 a/b/g Access Point (default IP address is when no DHCP server is answering its request).

Access Point Entry in clients.conf
client {
secret = testing123
shortname = liv1


The client statement specifies the access point's IP address. Its secret parameter specifies a string that your access point uses as an encryption key for all queries it sends to your FreeRADIUS server. shortname simply is an alias for your access point to be used in log entries and so on.
You now can (re)start freeradius by using the rc.radiusd script, for e0xample, rc.radiusd start or by typing freeradius -X -f.

Configuring the Access Point

The next step is the easiest part of this entire process: configure your wireless access point to use WPA and to point to your FreeRADIUS server. This requires only two pieces of information, the RADIUS secret you entered in your FreeRADIUS server's clients.conf file and the IP address of your FreeRADIUS server.
How you present those two pieces of information to your access point depends on your particular hardware and software. The access point used in this howto is a 3com 7760 configuring it via http is a piece of cake.

If your access point and RADIUS server are separated by a firewall, you need to allow the access point to reach the RADIUS server on UDP ports 1812 and 1813. Doing so also allows the RADIUS server to send packets back from those ports.

Configuring Windows XP Clients

Configuring a Windows XP wireless client to use your WPA-enabled access point.
In summary, you need to:
Run the command mmc from Start→Run....
In Microsoft Management Console, select File→Add/Remove Snap-in, add the Certificates snap-in and set it to manage certificates for My user account and, on the next screen, only for the Local computer.
Copy your CA (cacert.pem) certificate to your Windows system's hard drive, for example, to C:\cacert.pem.
From within MMC, expand Console Root and Certificates - Current User and right-click on Trusted Root Certification Authorities. In the pop-up menu, select All Tasks→Import. Tell the subsequent wizard to import the file C:\cacert.pem and to store it in Trusted Root Certification Authorities.
Copy your client certificate/key file to your Windows system, for example, to C:\client_cert.p12.
From within MMC→Console Root→Certificates, expand Personal and right-click on Certificates. In the pop-up menu, select All Tasks→Import. Tell the subsequent wizard to import the file C:\client_cert.p12.
The certificate-import wizard then prompts you for the certificate's passphrase. In the same dialog, it offers the option to enable strong private key protection. Unfortunately, enabling this breaks WPA, so be sure to leave this option unchecked. Also, leave the option to mark this key as exportable unchecked—you're better off backing up the password-protected file you just imported rather than allowing the imported nonprotected version to be exportable.
In the subsequent screen, let the wizard Automatically select the certificate store.
Now your Windows XP system is ready to go—all that remains is to create a wireless network profile. This, however, varies depending on your wireless card's drivers and which Windows XP Service Pack you're running. According to my little experience on using WPA entreprise on Windows XP, SP2 is a minimal requisite if you want a quite functional and stable connection. I set Network Authentication to WPA, Data encryption to TKIP and EAP type to Smart Card or other Certificate. Windows automatically determined which client certificate I used—this is because we took pains to create a client certificate that references Windows XP's extended attributes
After you configure your wireless network profile, your Windows system should connect automatically to your access point and negotiate a WPA connection. If this succeeds, Network Connections should show a status of Authentication succeeded for your Wireless Network Connection entry.