Freeradius and rlm_yubikey
One of the rlm_yubikey module’s functionalities is to check yubikey OTP token values against a cloud-based Yubico validation server.
Yubico OTP is a strong authentication mechanism, that can be used without any additional client-side software. You need Yubikey series 4 or 5. They just work as a USB keyboard to the operating system. No need to install any special drivers. The principle of operation is described here.
An example otp is as follows: ccccccukiegehhulguubvvcufvlnelicklfitvndnkeu
. The sequence as a whole is encoded using the so-called
Modhex code. The first 12 characters (ccccccukiege
) are always constant and represent the Yubikey ID. It is simply Yubikey’s serial number encoded in Modhex. In the freeradius configuration, we can assign one or more Yubikey IDs to a given user. The remaining 32 characters contain a AES-encryped variable and unique passcode.
In the presented example, the user’s password will consist of two connected parts: a permanent password and an otp. Suppose the user’s password is 0pa$$, then together with otp it will take the form: 0pa$$ccccccukiegehhulguubvvcufvlnelicklfitvndnkeu
.
To use the Yubico validation server, you must first register here. You’ll receive two parameters that will identify you: client_id and api_key.
Installation on Ubuntu 20.04 LTS
sudo apt-get install freeradius
sudo apt-get install freeradius-yubikey
Let’s modify the files below. For simplicity, the user database is in the users file. User fred has password 0pa$$ (hashed with salted SHA-512) and two Yubikeys assigned.
/etc/freeradius/3.0/mods-config/files/authorize:
fred SSHA2-512-Password := "R/yRaSHMPMQDipVoQNLh1NiAkkfyeXMu2ZD2QUEauW4g9yDOEWsbt+JkxNAEeGZd9GLxfcO7hmLLkN0thDFxh/Wvq9k="
Yubikey-Private-ID += "ccccccukiege",
Yubikey-Private-ID += "ccccccuhnvgr"
The rlm_yubikey module has a configuration file in which we complete the previously obtained parameters: client_id and api_key.
/etc/freeradius/3.0/mods-available/yubikey:
yubikey {
validate = yes
validation {
servers {
uri = 'https://api.yubico.com/wsapi/2.0/verify?id=%d&otp=%s'
uri = 'https://api2.yubico.com/wsapi/2.0/verify?id=%d&otp=%s'
}
client_id = 00000
api_key = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
pool {
start = ${thread[pool].start_servers}
min = ${thread[pool].min_spare_servers}
max = ${thread[pool].max_servers}
uses = 0
retry_delay = 30
lifetime = 0
idle_timeout = 60
spread = yes
}
}
}
Now we create a default virtual server configuration. Of course, below is an example file limited to a working minimum. We’ll name this file yubikey_test and put it in the sites_available directory.
/etc/freeradius/3.0/sites-available/yubikey_test:
server default {
listen {
type = auth
ipaddr = *
port = 0
}
authorize {
yubikey
if (ok) {
update control {
Auth-Type := yubikey
}
}
files
}
authenticate {
Auth-Type yubikey {
yubikey
pap
update request {
Yubikey-Private-Id := Yubikey-Public-ID
}
}
}
post-auth {
#check that the yubikey used is assigned to this user
if (&Yubikey-Private-Id != &reply:Yubikey-Private-ID[*]) {
update reply {
Reply-Message := "Token not allowed for use by user %{User-Name}"
}
reject
}
#remove list of Yubikey Private IDs from the reply
update reply{
Yubikey-Private-ID !* ANY
}
#remove attributes in case of reject
Post-Auth-Type REJECT {
attr_filter.access_reject
}
}
}
Next, we link the configuration file in sites-enabled. If necessary, we remove unnecessary links from here:
sudo ln -s /etc/freeradius/3.0/sites-available/yubikey_test /etc/freeradius/3.0/sites-enabled/
You also need to link the yubikey module in mods-enabled. If we don’t use eap, we also remove the link to the eap module:
sudo ln -s /etc/freeradius/3.0/mods-available/yubikey /etc/freeradius/3.0/mods-enabled/
sudo rm /etc/freeradius/3.0/mods-enabled/eap
Now we can start testing. It’s best to do this on two consoles. On the first one, we run freeradius in debug mode (sudo freeradius -X
).
On the next console, let’s create a simple script that combines the user’s password and otp read from Yubikey:
#!/bin/bash
PASS='0pa$$'
echo Tap Yubikey
read OTP
radtest fred $PASS$OTP 127.0.0.1 100 testing123
Run it and touch the button on Yubikey. If you use a Yubikey which is assigned to a user (see the ‘authorize’ file above) you should get:
Tap Yubikey
ccccccuhnvgrkeerurgejjdubburvfrrbgvnjkfjfdvv
Sent Access-Request Id 132 from 0.0.0.0:32913 to 127.0.0.1:1812 length 122
User-Name = "fred"
User-Password = "0pa$$ccccccuhnvgrkeerurgejjdubburvfrrbgvnjkfjfdvv"
NAS-IP-Address = 10.0.0.3
NAS-Port = 100
Message-Authenticator = 0x00
Cleartext-Password = "0pa$$ccccccuhnvgrkeerurgejjdubburvfrrbgvnjkfjfdvv"
Received Access-Accept Id 132 from 127.0.0.1:1812 to 127.0.0.1:32913 length 20
In case of using Yubikey not assigned to the user, you’ll get:
(…)
Received Access-Reject Id 224 from 127.0.0.1:1812 to 127.0.0.1:54164 length 60
Reply-Message = "Token not allowed for use by user fred"
If you try to reuse otp, you’ll get Access-Reject
and in debug on the first console yubikey: ERROR: Yubikey OTP was replayed (REPLAYED_OTP)
.
Likewise, in the event of a mismatch of the user password (0pa$$
) or otp you’ll get an Access-Reject
.