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.