Next step in my investigations to implement a strong authentication process on my Linux laptop using the Yubikey. In a previous post, I explained how to use a Yubikey to authenticate on Linux with a PAM module. It works very well but, like I said in the previous article conclusion, strong authentication has to be implemented otherwise, anybody could unlock or log in your system just using your key.
Remember, strong authentication is achieved when you combine at least two different factors like: something you know (your password), something you have (your Yubikey) or something you are (your fingerprint). In the example below, we will use a Yubikey OTP and a PIN code (4 characters).
When searching for useful information, I found a post on the Yubico forum about a patch to implement a PIN code (check the topic here). I contacted the author and asked for more details. Greg provided me his patch but I decided to write my own after a brief analysis. Anyway, thanks Greg!
My goal was to implement a PIN code in the same way commercial products do (big names like “R?A” or “V?SC?”). The password given by the user must respect the following format:
9999AAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
A 4-characters PIN code (“9”), the 12-characters Yubikey ID (“A”) and the one time password (“B”). Note that I decided to not restrict the PIN code to numbers ([0-9]). It can contains also letters and signs! My patch is based on a standard YubiPAM source tree. If you check into the C headers file “yubikey_db.h“, you will see that the developers already defined an extra zone in the DB structure named “reserved”:
struct _ykdb_entry_ticket { uint8_t key[YKDB_KEY_BYTE_SIZE]; uint8_t private_uid_hash[32]; uint16_t last_use; uint8_t last_timestamp_hi; uint16_t last_timestamp_lo; uint8_t last_session; uint8_t reserved[42]; } __attribute__((__packed__)); typedef struct _ykdb_entry_ticket ykdb_entry_ticket;
I use this space to store a hash (SHA256) of the recorded PIN code. As the DB is encrypted using AES, there is no risk of disclosure (no storage of any PIN code in clear text).
The PAM module itself is not patched: The verification of the one time password is performed by a helper called “yk_chkpwd“. Only two utilities have been patched:
- ykpasswd – to assign a Yubikey (and now a PIN code) to a local user account.
- yk_chkpwd – to validate the Yubikey (and not the PIN code).
Apply my patch to a clean YubiPAM-1.0.4 source tree and recompile everything:
# cd /tmp # tar xvpf YubiPAM-1.0.4.tar.gz # cd YubiPAM-1.0.4 # wget https://blog.rootshell.be/wp-content/uploads/2009/04/\ YubiPAM-PIN.patch # patch -p0 <YubiPAM-PIN.patch # ./configure # make install # more README
We are now ready to register our Yubikey and link it to the local user (For a complete description of this process, check my previous post):
# ykpasswd -a -u <user> -k <easkey> -i <pincode> -o <otp>
Note the new parameter “-i” to specify your PIN code. Once done, try to authenticate yourself:
# ykvalidate -u <user> <otp>
Where OTP is your PIN concatenated with the OTP. If it worked (“VALID” response), you’re ready to authenticate against all services compatible with PAM. When a prompt for a password is displayed, type your PIN code and press the circle green button on your Yubikey and you’re in! Enjoy!
Important remarks:
- There is no way to update the PIN code at the moment. You need to delete the registered Yubikey and add it once again in the DB.
- Once patched, the authentication will ALWAYS require a PIN code (the PIN code is not optional)
Download the patch (SHA1 digest: 54f73f88e75ff26c6f2add355d2716251c6b0395)
Hi,
Sorry for the false report: it seems I messed up something, the PIN may indeed contain arbitrary characters.
Best Regards,
Jozsef
Hi,
Thanks for your patch for PIN support in YubiPAM! I have tried it and it works great, except one little thing: it seems arbitrary PIN cannot be used. At least I was unable to validate when the PIN contained any non-hex characters.
Best regards,
Jozsef