802.1x on Linux with xsupplicant

by Matthew Gast

When WEP's flaws became apparent, the wireless industry started developing new protocols to address the published weak points. These new protocols grew up around the IEEE 802.1x framework, which is a way of using the Extensible Authentication Protocol (EAP) and all of its methods on a LAN link. 802.1x client software programs, called supplicants, were brought to market by operating system vendors as well as by third-party developers.

Linux, however, initially was left out of the 802.1x frenzy. Network administrators who supported power users were forced to rely on manual WEP-based solutions with MAC address filtering or VPNs to secure Linux before supplicants were widely available. Happily, now two open-source supplicants are bringing high-quality wireless security to Linux. This article describes the process of setting up xsupplicant, which is also known as Open1X.

Wireless Extensions

The wireless extensions API originally was designed to provide a unified way of having programs interact with drivers. Like any API, it saves developers from having to know the details of how to interact with every card. 802.1x supplicants, for example, are able to use a wireless extensions system call to set keys, rather than using card-specific calls for every card that exists.

The wireless extensions interface has gone through several versions. WPA support was added in wireless extensions version 18 (WE-18). Some distributions using the 2.6 kernel already have WE-18 support. Older kernels need to be patched, however. My test laptop runs Slackware, which still is using the 2.4 kernel. The 2.4 kernel has support for version 16 of wireless extensions, but patches are available for version 2.4.30. Patch download locations appear in the on-line Resources for this article. Begin by applying two patches to the kernel source:

# patch -p1 ~/iw249_we17-13.diff
patching file include/linux/netdevice.h
patching file include/linux/wireless.h
patching file include/net/iw_handler.h
patching file net/core/dev.c
patching file net/core/wireless.c
# patch -p1 ~/iw240_we18-5.diff
patching file include/linux/wireless.h
patching file net/core/wireless.c

To keep modules straight, I often find it helpful when patching kernels to edit the Makefile to include an extra version number in addition to the patch level. My wireless extensions 18 kernel is built as 2.4.30WE18.

The most common tools used with wireless extensions are the wireless toolset, and the most common tool you will use is iwconfig. Wireless tools version 28 is the current version and supports WE-18. Grab the source code from the Web site (see Resources). A simple make command builds the tools.

Getting the Driver Going

Many cards are supported under Linux, but a handful of drivers have captured the bulk of the popularity:

  • MADwifi, the Multi-band Atheros Driver for Wi-Fi: Atheros-based cards have some of the best hardware support for 802.11a networking. Chances are good that if your card supports 802.11a, it uses an Atheros-designed chip.

  • Intel IPW drivers for Centrino chipsets: Intel sponsors open-source driver development projects for the various Centrino chipsets. Due to the sheer number of Centrino chipsets on the market, these drivers are widely used.

  • orinoco_cs: the first widely used 802.11 card was the Orinoco Gold card, based on the Hermes chipset. These cards were sold under a variety of names, and they all performed quite well in their day. Although the radio performance and throughput of these cards is no longer cutting-edge, the driver is well understood and often serves as a testbed for new ideas.

This article is not meant to be a definitive treatment of working with drivers. I use Atheros-based cards because I have an 802.11a network at home and want a dual-band card for packet analysis. Therefore, I am writing about MADwifi.

MADwifi has not released any packaged source files. To use the driver, you must download the code from CVS. The build files distributed with MADwifi use your current kernel. If you have patched the kernel to update wireless extensions, reboot before building MADwifi:

$ cvs -z3 -d:pserver:anonymous@cvs.sourceforge.net:
↪/cvsroot/madwifi co madwifi
$ cd madwifi
$ make

root@bloodhound:/home/user/madwifi# make install

Atheros-based cards do not use firmware. Instead, they have a binary-only object called the hardware abstraction layer (HAL). Atheros has interpreted FCC regulations in such a way that requires the HAL to be kept closed-source. The HAL serves the same purpose as firmware on other cards—it implements low-level operations for the driver. The HAL is distributed as a uuencoded file, so you must install the uudecode program to install the HAL. It probably is in the shell archive utilities package for your distribution, but the location may vary. The OpenBSD Atheros driver includes an open-source, reverse-engineered HAL, but it has not been ported yet to Linux.

The kernel modules built as part of the process are installed in your modules directory. The driver includes its own 802.11 support layer composed of the modules wlan, wlan_wep, wlan_tkip and so on. The hardware-specific part of MADwifi is composed of modules that begin with the prefix ath_: the driver ath_pci, the HAL ath_hal and rate adaptation algorithms (ath_rate_*). All the modules are installed in the net/ directory.

Testing the Driver

In addition to having up-to-date wireless support in the kernel, you need to have a properly configured wireless networking subsystem. Many “wireless” problems encountered when dealing with 802.1x on Linux are PC card configuration problems. When the card is inserted, you should get a high-pitched beep indicating that Card Services has loaded the right driver. A second beep is used to communicate the status of the card configuration, so a second lower beep is fine because the configuration of the card hasn't been set up yet.

If the card is recognized and the right driver is loaded, try firing up a wireless network with no encryption and no authentication. Configure association to the network with iwconfig, and bring up the card with ifconfig. The MADwifi driver creates interfaces that begin with the prefix ath, so my interface is ath0. Depending on the driver you use, your interface may be different. When the card first comes up, you can see it scan for the network as the frequency reported by iwconfig changes. When the card successfully associates to a network, it reports the access point MAC address as well as the operating frequency. At that point, you should be able to ask the network for an IP address, using whatever tool is favored by your Linux distribution:

# iwconfig ath0 essid "clearnet"
# ifconfig ath0 up
# iwconfig ath0
ath0  IEEE 802.11g  ESSID:"etherclear"
      Mode:Managed  Frequency:2.412 GHz  Access Point: 00:0B:0E:2F:0A:40
      Bit Rate:12 Mb/s   Tx-Power:50 dBm   Sensitivity=0/3
      Retry:off   RTS thr:off   Fragment thr:off
      Power Management:off
      Link Quality=39/94  Signal level=-56 dBm  Noise level=-95 dBm
      Rx invalid nwid:107  Rx invalid crypt:0  Rx invalid frag:0
      Tx excessive retries:22  Invalid misc:22   Missed beacon:0
# dhcpcd -d -t 10 ath0
dhcpcd: MAC address = 00:20:a6:4c:ca:4b
dhcpcd: your IP address =

If you can associate to a network, your card is functional. Although it is not necessary to find out if you can obtain an IP address from an unencrypted network, it is helpful to know that the frame handling and network stacks are working and that DHCP service is configured correctly on the network. With the wireless network system having basic functionality, we can move on to providing security for it.


Two major supplicants exist for Linux: xsupplicant, also known as Open1X, and wpa_supplicant. This article discusses only the former. Before getting to work on xsupplicant, check the version of OpenSSL on your system. xsupplicant requires OpenSSL 0.9.7 or later to provide transport layer security (TLS) support. All the commonly used 802.1x authentication protocols require TLS, either for authentication directly with digital certificates (EAP-TLS) or as a protective tunnel for some other form of authentication (TTLS or PEAP). You need a development version of the packages to get the expected headers.

Download the source code from SourceForge (see Resources) At the time of this writing, the current release is 1.2pre1:

$ tar -xzf Xsupplicant-1.2pre1.tar.gz
$ cd xsupplicant
$ ./configure --with-madwifi-path=~/madwifi
. . .
Adding MADWIFI WPA support.
. . .
$ make

# make install

As a result of the build, three executables are installed. The only one you are likely to use is /usr/local/sbin/xsupplicant.

Certificate Wrestling

Secured EAP authentication generally depends on digital certificates. Certificate data is encoded using either the privacy-enhanced mail (PEM) format or the distinguished encoding rules (DER). My experience is that xsupplicant likes its certificates in PEM format, but many certificate authorities hand out certificates in the DER format. Fortunately, OpenSSL is quite good at converting between formats:

# openssl x509 -inform DER -outform PEM \
-in MyCA.der -out MyCa.pem

To see the actual data encoded within the certificate, you can use the openssl command to print textual output:

# openssl x509 -in MyCA.pem -text

How exactly you obtain the certificate is up to your network administrator. Many certificate authorities make the root certificate available on a Web page.

Configuring xsupplicant

When run, xsupplicant searches for its configuration file in /etc. The config file, /etc/xsupplicant.conf, is not installed by default, but it's easy enough to copy over:

# cp xsupplicant.conf /etc/xsupplicant.conf

Specify the user identity, possibly the password and the root CA certificate in the configuration file. Each network can have its own configuration by bracketing the entire network configuration. A simple configuration for a network that uses PEAP with MSCHAP-V2 for inner authentication might look something like this:

  identity = testuser
  eap_peap {
      root_cert = /usr/local/etc/myCA.der
      random_file = /path/to/random/source
      allow_types = eap_mschapv2
      eap-mschapv2 {
        username = testuser
        password = "testpw"

Linux has two random number devices, /dev/random and /dev/urandom. Both pull random numbers from a system entropy pool, but the former device returns only strong random numbers. As a result, I highly recommend using /dev/random as the random number device file. Many 802.1x implementations can cope with relatively large delays while waiting for a response. At the Interop Labs in Las Vegas in May 2005, we authenticated a user account through a multi-hop global distributed RADIUS system, so end-to-end latency was much higher than on most networks.

For testing purposes, certificate validation can be disabled by setting the root_cert location to NONE. Although useful for testing purposes, disabling certificate authentication removes the protections provided by the certificate and should not be done for normal deployments.

Running xsupplicant

Once xsupplicant is configured, you finally can authenticate to the network. Start by connecting to the network that you want to attach to with iwconfig and bringing up the interface. I have found that it helps to give xsupplicant a dummy WEP key so it knows that it will be connecting to an encrypted network as well. Three commands do the trick:

# iwconfig ath0 key 12345678901234567890123456
# iwconfig essid "batnet"
# ifconfig ath0 up

The wireless interface name is driver-dependent. My interface is ath0, but yours may not be.

In the current version of xsupplicant, it is mandatory to supply an interface with the -i option. When testing, I generally find it helpful to log debug messages with -d and keep the process in the foreground with -f. To see a full list of what can be printed, use --help:

# xsupplicant -w -dasic -i ath0 -f

Debug messages print out each frame that is sent and received, as well as provide processing information with each sent or received frame. At the end of the process, the key information is processed. For example, a dynamic WEP key looks like this:

Processing EAPoL-Key!
[INT] Key Descriptor   = 1
[INT] Key Length       = 13
[INT] Replay Counter   = 41 2F BB 2D 00 00 00 D6
[INT] Key IV           = 66 15 69 E2 B2 8C 0E 89 7C D3 94 8C 93 25 43 1B
[INT] Key Index (RAW)  = 80
[INT] Key Signature    = 49 C1 15 B8 E9 D0 87 53 A6 FD 5D 76 CB 51 9D 65
[INT] EAPoL Key Processed: unicast [1] 13 bytes.
[INT] Using peer key!
[INT] Successfully set WEP key [1]
[INT] Successfully set the WEP transmit key [1]
Configuring and Using WPA

WPA is triggered by a command-line option and is configured by two options in the global section of the configuration file. WPA allows you to specify the type of encryption used for unicast (pairwise) and broadcast or multicast (group) frames. Both options can be set in the configuration file and can take values of wep40, wep104, tkip, ccmp or wrap. At this point, however, only the RC4-based ciphers—WEP and TKIP—work reliably. Set up the two lines of configuration like this:

wpa_pairwise_cipher = tkip
wpa_group_cipher = tkip

  . . .

To use WPA at run time, you must have configured support in the driver for your card as well as the main configuration file. WPA is not simply the new encryption routines of TKIP and it does affect the association process and key distribution. Due to the level of driver support required, you need to specify a driver with the -D option, and you must use a driver that has WPA support compiled in:

# xsupplicant -dasic -i ath0 -D madwifi

Resources for this article: /article/8404.

Matthew Gast is the author of the leading technical book on wireless LANs, 802.11 Wireless Networks: The Definitive Guide (O'Reilly Media). He currently is Director of Consulting Engineering for an advanced wireless systems company, where he helps customers understand new security protocols and standards and how to use them to build secure wireless LANs. He can be reached at matthew.gast@gmail.com, but only when he is close to sea level.

Load Disqus comments