Linux – Managing WiFi with wpa_supplicant


To totally unlock this section you need to Log-in

wpa_supplicant is a WPA Supplicant for Linux, BSD, Mac OS X, and Windows with support for WPA and WPA2 (IEEE 802.11i / RSN). It is suitable for both desktop/laptop computers and embedded systems. Supplicant is the IEEE 802.1X/WPA component that is used in the client stations. It implements key negotiation with a WPA Authenticator and it controls the roaming and IEEE 802.11 authentication/association of the wlan driver.

In almost all modern home wireless network, communications are protected with WPA-PSK (pre-shared key) or, better, WPA2-PSK as opposed to WPA-Enterprise, which is designed for enterprise networks and usually requires specific server roles to be issued correctly.

WPA-PSK/WPA2-PSK is also known as WPA/WPA2-Personal. wpa_supplicant is an implementation of the WPA supplicant component. A supplicant in wireless LAN is a client software installed on end-user’s computer that needs to be authenticated in order to join a network.

Following steps are used when associating with an AP using WPA:

  1. wpa_supplicant requests the kernel driver to scan neighboring BSSes.
  2. wpa_supplicant selects a BSS based on its configuration.
  3. wpa_supplicant requests the kernel driver to associate with the chosen BSS.
  4. If WPA-EAP: integrated IEEE 802.1X Supplicant completes EAP authentication with the authentication server (proxied by the Authenticator in the AP).
  5. If WPA-EAP: master key is received from the IEEE 802.1X Supplicant.
  6. If WPA-PSK: wpa_supplicant uses PSK as the master session key.
  7. wpa_supplicant completes WPA 4-Way Handshake and Group Key Handshake with the Authenticator (AP). WPA2 has integrated the initial Group Key Handshake into the 4-Way Handshake.
  8. wpa_supplicant configures encryption keys for unicast and broadcast.
  9. Normal data packets can be transmitted and received.

Enable wireless interface

In order to configure wireless connectivity on Linux the network interface is needed .To discover the network interface use the ip command. Running ip a will show all of the network interfaces, wired and wireless, available on the machine.

ip a

The wireless interface on the machine, as output, could be, for example, wlan0 (but it can differs but usually a wireless card will begin with a w character). If the wireless interface is not present and the machine has a wireless card it is possible that the driver for the wireless card is not installed yet.

Another way to find the wireless interface is by using iwconfig command.

Another way to check if the wireless card is enabled is using rfkill.

sudo apt install rfkill

To check the status of wireless card, we run:

rfkill list

If in the output it says that Hard blocked is no and Soft blocked is yes we can unblock the wireless card by using:

rfkill unblock wifi

If we are using the desktop version of Ubuntu, then you also need to stop Network Manager with the following command, otherwise it will cause connection problem when using wpa_supplicant.

sudo systemctl stop NetworkManager

We also need to disable NeworkManager start at boot time by executing the following command:

sudo systemctl disable NetworkManager

Once we have identified the wireless interface name, we can find the nearby networks beginning a scan using the command below. We just need to use our wireless interface name, if different from wlan0, with our own interface name. ESSID means network name (Extended basic Service Set IDentifier).

sudo iwlist wlan0 scan | grep ESSID

Now we will take note of the ESSID to which we want to connect (if the ESSID contains any white space it is recommended to keep it included into double quotes).

Install and connect to Wi-fi network using wpa_supplicant

Now install wpa_supplicant on an Ubuntu/Debian system.

sudo apt-get install wpasupplicant

After the installation of the package we will need to create a file named wpa_supplicant.conf, if not already present, using the wpa_passphrase utility.

wpa_supplicant.conf is the configuration file describing all networks that the user wants the computer to connect to. Run the following command to create this file.

Replace ESSID and Wi-fi passphrase with your own.

wpa_passphrase your-ESSID your-passphrase | sudo tee /etc/wpa_supplicant.conf

The output will be piped to tee which then write to /etc/wpa_supplicant.conf file. Now use the following command to connect your wireless card to wireless access point.

sudo wpa_supplicant -c /etc/wpa_supplicant.conf -i wlp3s0

By default, wpa_supplicant runs in the foreground. If the connection is completed, then open up another terminal window and run:

iwconfig

If it has been all ok, we will see that the wireless interface is now associated with an access point (we will notice the tx-power, bit-rate class information, etc.).

Now we can press CTRL+C to stop the current wpa_supplicant process and run it in the background by adding -B option.

sudo wpa_supplicant -B -c /etc/wpa_supplicant.conf -i wlp3s0

Now we are associated to the access point, but this does not mean that we have already an IP address and netmask delivered, in fact, we’re just authenticated and connected to wireless network.

To obtain a private IP address from the local DHCP server, use the following command:

sudo dhclient wlan0

Now your wireless interface will ask the access point, with a DHCP discover/request, to be able to get a private IP address by an available local DHCP server (in small/home offices the access point is usually also a DHCP server), which can be shown with:

ifconfig wlan0

Now you can access the Internet. To release the private IP address, we can run (this can be useful if we want to troubleshoot DHCP server, but not needed for regular users):

sudo dhclient wlan0 -r

Connecting to Hidden Wireless Network

If your wireless doesn’t broadcast ESSID, then you need to add the following line in /etc/wpa_supplicant.conf file.

scan_ssid=1
Like below:

network={
        ssid="LinuxBabe.Com office network"
        #psk="12345qwert"
        psk=68add4c5fee7dc3d0dac810f89b805d6d147c01e281f07f475a3e0195
        scan_ssid=1
}

Auto Connect on Startup

To automatically connect to wireless network at boot time, we need to edit the wpa_supplicant.service file. It’s a good idea to copy the file from /lib/systemd/system/ directory to /etc/systemd/system/ directory, then edit it because we don’t want newer version of wpasupplicant to override our modifications.

sudo cp /lib/systemd/system/wpa_supplicant.service /etc/systemd/system/wpa_supplicant.service
sudo nano /etc/systemd/system/wpa_supplicant.service

Find the following line:

ExecStart=/sbin/wpa_supplicant -u -s -O /run/wpa_supplicant

Change it to the following. Obviously you need to change wlp3s0 if that isn’t your interface name:

ExecStart=/sbin/wpa_supplicant -u -s -c /etc/wpa_supplicant.conf -i wlan0

If you can find the following line in this file, comment it out (just adding the # character at the beginning of the line):

Alias=dbus-fi.w1.wpa_supplicant1.service

Save and close the file. Then enable wpa_supplicant service to start at boot time.

sudo systemctl enable wpa_supplicant.service

We also need to start dhclient at boot time to obtain a private IP address ant the other network info from the DHCP server. This can be achieved by creating a systemd service unit for dhclient.

sudo nano /etc/systemd/system/dhclient.service

Put the following text into the file:

[Unit]
Description= DHCP Client
Before=network.target

[Service]
Type=simple
ExecStart=/sbin/dhclient wlan0 -v
ExecStop=/sbin/dhclient wlan0 -r

[Install] 
WantedBy=multi-user.target

Save and close the file. Then enable this service by uissuing the following command:

sudo systemctl enable dhclient.service

Interact with wpa_supplicant using wpa_cli

The wpa_cli command can be used to interact with wpa_supplicant. It can be used to query current status, change configuration, trigger events, and request interactive user input.

NOTE: If, for example, the GROUP=wheel option is set in the wpa_supplicant configuration, for example as ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=wheel, the command may be run by users in the wheel group.

If not it must be run as root.

wpa_cli
wpa_cli v2.5
Copyright (c) 2004-2015, Jouni Malinen  and contributors

This software may be distributed under the terms of the BSD license.
See README for more details.

Selected interface 'wlp3s0b1'

Interactive mode

>

Once launched the tool will be in interactive mode.

To scan for networks using wpa_cli at the interactive prompt first run scan.

> scan
OK
<3>CTRL-EVENT-SCAN-STARTED
<3>CTRL-EVENT-SCAN-RESULTS
<3>WPS-AP-AVAILABLE
<3>CTRL-EVENT-NETWORK-NOT-FOUND

Once the CTRL-EVENT-SCAN-RESULTS event has been received run scan_results.

> scan_results
bssid / frequency / signal level / flags / ssid
7c:4c:a5:68:25:69       2412    7       [WPA2-PSK-CCMP][WPS][ESS]       SKY1DA97
92:d3:f7:4d:47:00       2437    7       [WPA-EAP-CCMP+TKIP][WPA2-EAP-CCMP+TKIP][ESS] BTWifi-X
a8:d3:f7:4d:47:06       2437    7       [WPA2-PSK-CCMP][WPS][ESS]       BTHub5-H9MS
f4:f2:6d:85:6d:bf       2412    7       [WPA-PSK-CCMP+TKIP][WPA2-PSK-CCMP+TKIP][WPS][ESS]     SKY43B9E
00:50:7f:eb:1c:40       2462    7       [WPA-PSK-CCMP+TKIP][WPA2-PSK-CCMP+TKIP][ESS] MYNETWORK

The results list five columns and allow the available networks to be seen. The flags column is particularly useful showing the security model for the network.

To connect to a network using wpa_cli first add a new network and then set the SSID and passphrase.

> add_network
0
> set_network 0 ssid "MYNETWORK"
> set_network 0 psk "secret"

The ssid value related to the ssid value discovered during the scan. The psk value is the pre-shared key for the wireless network (the password). Once these parameters are set the network is ready to use.

> enable_network 0
0K
<3>CTRL-EVENT-SCAN-STARTED
<3>CTRL-EVENT-SCAN-RESULTS
<3>WPS-AP-AVAILABLE
<3>SME: Trying to authenticate with 00:50:7f:eb:1c:40 (SSID='MYNETWORK' freq=2462 MHz)
<3>Trying to associate with 00:50:7f:eb:1c:40 (SSID='MYNETWORK' freq=2462 MHz)
<3>Associated with 00:50:7f:eb:1c:40
<3>WPA: Key negotiation completed with 00:50:7f:eb:1c:40 [PTK=CCMP GTK=TKIP]
<3>CTRL-EVENT-CONNECTED - Connection to 00:50:7f:eb:1c:40 completed [id=0 id_str=]

To save wpa_configuration using wpa_cli use save_config at the interactive prompt.

> save config
OK

Examining the configuration file shows that the network configuration has been written to the file.

cat /etc/wpa_supplicant/wpa_supplicant.conf

ctrl_interface=DIR=/run/wpa_supplicant
update_config=1

network={
        ssid="MYNETWORK"
        psk="secret"
}

Now if the machine is rebooted wpa_supplicant can be started as before and it will connect to the MYNETWORK wireless network.

wpa_supplicant -B -i wlan0 -c /etc/wpa_supplicant/wpa_supplicant.conf

Quick Tip

You can quickly append new networks to the wpa_supplicant file fairly easily with command line interface. For example, in the following command, replace SSID with the full name of the network you wish to connect to, and PASSWORD with the password of the network:

$ wpa_supplicant "SSID" "PASSWORD" >> /etc/wpa_supplicant/wpa_supplicant.conf

This will append the network info to the end of the wpa_supplicant configuration file. You will need to restart networking once you've done this.

Example Configurations

The following are some of typical configurations for wpa_supplicant.

# Plaintext (no encryption) network

ctrl_interface=/var/run/wpa_supplicant

network={
	ssid="example open network"
	key_mgmt=NONE
}

# Static WEP keys

ctrl_interface=/var/run/wpa_supplicant

network={
	ssid="example wep network"
	key_mgmt=NONE
	wep_key0="abcde"
	wep_key1=0102030405
	wep_tx_keyidx=0
}

# IEEE 802.1X with dynamic WEP keys using EAP-PEAP/MSCHAPv2

ctrl_interface=/var/run/wpa_supplicant

network={
	ssid="example 802.1x network"
	key_mgmt=IEEE8021X
	eap=PEAP
	phase2="auth=MSCHAPV2"
	identity="user name"
	password="password"
	ca_cert="/etc/cert/ca.pem"
}

# WPA-PSK/TKIP

ctrl_interface=/var/run/wpa_supplicant

network={
	ssid="example wpa-psk network"
	key_mgmt=WPA-PSK
	proto=WPA
	pairwise=TKIP
	group=TKIP
	psk="secret passphrase"
}

# WPA2-EAP/CCMP using EAP-TLS

ctrl_interface=/var/run/wpa_supplicant

network={
	ssid="example wpa2-eap network"
	key_mgmt=WPA-EAP
	proto=WPA2
	pairwise=CCMP
	group=CCMP
	eap=TLS
	ca_cert="/etc/cert/ca.pem"
	private_key="/etc/cert/user.p12"
	private_key_passwd="PKCS#12 passhrase"
}

WPA-Personal (PSK) as home network and WPA-Enterprise with EAP-TLS as work network:

# allow frontend (e.g., wpa_cli) to be used by all users in 'wheel' group

ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=wheel

# home network; allow all valid ciphers
network={
        ssid="home"
        scan_ssid=1
        key_mgmt=WPA-PSK
        psk="very secret passphrase"
}

# work network; use EAP-TLS with WPA; allow only CCMP and TKIP ciphers
network={
        ssid="work"
        scan_ssid=1
        key_mgmt=WPA-EAP
        pairwise=CCMP TKIP
        group=CCMP TKIP
        eap=TLS
        identity="user [at] example.com"
        ca_cert="/etc/cert/ca.pem"
        client_cert="/etc/cert/user.pem"
        private_key="/etc/cert/user.prv"
        private_key_passwd="password"
}

Certificates (EAP Authentication)

Some EAP authentication methods require use of certificates.

EAP-TLS uses both server side and client certificates whereas EAP-PEAP and EAP-TTLS only require the server side certificate.

When client certificate is used, a matching private key file has to also be included in configuration. If the private key uses a passphrase, this has to be configured in wpa_supplicant.conf ("private_key_passwd").

wpa_supplicant supports X.509 certificates in PEM and DER formats. User certificate and private key can be included in the same file.

If the user certificate and private key is received in PKCS#12/PFX format, they need to be converted to suitable PEM/DER format for wpa_supplicant. This can be done, e.g., with following commands:

# convert client certificate and private key to PEM format
openssl pkcs12 -in example.pfx -out user.pem -clcerts
# convert CA certificate (if included in PFX file) to PEM format
openssl pkcs12 -in example.pfx -out ca.pem -cacerts -nokeys

Encrypting password in wpa_supplicant.conf

Open the wpa-supplicant configuration file in nano:

sudo nano /etc/wpa_supplicant/wpa_supplicant.conf

Go to the bottom of the file and add the following:

network={
    ssid="testing"
    psk="testingPassword"
}

The password can be configured either as the ASCII representation, in quotes as per the example above, or as a pre-encrypted 32 byte hexadecimal number. You can use the wpa_passphrase utility to generate an encrypted PSK.

This takes the SSID and the password, and generates the encrypted PSK. With the example from above, you can generate the PSK with wpa_passphrase "testing". Then you will be asked for the password of the wireless network (in this case testingPassword).

The output is as follows:

  network={
      ssid="testing"
      #psk="testingPassword"
      psk=131e1e221f6e06e3911a2d11ff2fac9182665c004de85300f9cac208a6a80531
  }

Note that the plain text version of the code is present, but commented out. You should delete this line from the final wpa_supplicant file for extra security.

The wpa_passphrase tool requires a password with between 8 and 63 characters.

To use a more complex password, you can extract the content of a text file and use it as input for wpa_passphrase. Store the password in a text file and input it to wpa_passphrase by calling wpa_passphrase "testing" < file_where_password_is_stored.

For extra security, you should delete the file_where_password_is_stored afterwards, so there is no plain text copy of the original password on the system.

Network Priority

If we have defined multiple WiFi networks into wpa_supplicant.conf and we have, for example, two networks in range, we can add the priority option to choose between them.

The network in range, with the highest priority, will be the one that is connected.

network={
    ssid="Public"
    psk="passwordOne"
    priority=1
    id_str="publ"
}

network={
    ssid="Private"
    psk="passwordTwo"
    priority=2
    id_str="priv"
}