The PAM module can utilize the HMAC-SHA1 Challenge-Response mode found in YubiKeys starting with version 2.2 for offline authentication. This mode is useful if you don’t have a stable network connection to the YubiCloud.
The ykpamcfg utility currently outputs the state information to a file
in the current user’s home directory ($HOME/.yubico/challenge-123456
for a YubiKey with serial number API readout enabled, and
$HOME/.yubico/challenge
for one without).
The PAM module supports a system-wide directory for these state files
(in case the user’s home directories are encrypted), but in a system-wide
directory, the challenge part should be replaced with the
username. Example: /var/yubico/alice-123456
.
To use the system-wide mode, you currently have to move the generated state files manually and configure the PAM module accordingly.
The following process is tested on Ubuntu 12.04.
First install the package:
sudo apt-get install libpam-yubico
You will get a question about the PAM configuration line. Enter this line:
mode=challenge-response
The next question will be about which PAM modules to enable. Don’t enable anything just yet, because you need to program your YubiKey first.
If you have already installed the package or want to reconfigure it, you may use this command:
sudo dpkg-reconfigure libpam-yubico
The next step is to add a challenge-response slot to your YubiKey. If you have a normal YubiKey with OTP functionality on the first slot, you could add Challenge-Response on the second slot. You could have CR on the first slot, if you want.
First, program a YubiKey for challenge response on Slot 2:
ykpersonalize -2 -ochal-resp -ochal-hmac -ohmac-lt64 -oserial-api-visible ... Commit? (y/n) [n]: y $
Now, set the current user to require this YubiKey for logon:
mkdir $HOME/.yubico ykpamcfg -2 -v ... Stored initial challenge and expected response in '/home/alice/.yubico/challenge-123456'. $
From security perspective, it is generally a good idea to move the challenge file in a system-wide path that is only read- and writable by root. To do this do as follow:
sudo mkdir /var/yubico sudo chown root.root /var/yubico sudo chmod 700 /var/yubico ykpamcfg -2 -v ... Stored initial challenge and expected response in '$HOME/.yubico/challenge-123456'. sudo mv ~/.yubico/challenge-123456 /var/yubico/alice-123456 sudo chown root.root /var/yubico/alice-123456 sudo chmod 600 /var/yubico/alice-123456
It is important that the file is named with the name of the user that is going to be authenticated by this YubiKey.
Finally we tell the pam module where to look for the challenge file
emacs /etc/pam.d/common-auth
and edit the following line as follow:
auth required pam_yubico.so mode=challenge-response chalresp_path=/var/yubico
Then back to the PAM configuration step, first make sure you have a root terminal available to be able to disable YubiKey login in case of issues.
sudo -s
Then run the "pam-auth-update" command and enable the Yubico PAM module.
sudo pam-auth-update
You should now be able to authenticate using YubiKey Challenge-Reseponse together with a password like this:
jas@latte:~$ sudo -s [sudo] password for jas: root@latte:~#
Now remove the YubiKey and try again (in a new terminal to avoid sudo caching), and you should not be able to login.
For debugging, you can make the PAM configuration line:
mode=challenge-response debug
and then create a log file:
touch /var/run/pam-debug.log chmod go+w /var/run/pam-debug.log
and then tail the file. For successful logins it should print something like this:
[pam_yubico.c:parse_cfg(721)] called. [pam_yubico.c:parse_cfg(722)] flags 32768 argc 2 [pam_yubico.c:parse_cfg(724)] argv[0]=mode=challenge-response [pam_yubico.c:parse_cfg(724)] argv[1]=debug [pam_yubico.c:parse_cfg(725)] id=-1 [pam_yubico.c:parse_cfg(726)] key=(null) [pam_yubico.c:parse_cfg(727)] debug=1 [pam_yubico.c:parse_cfg(728)] alwaysok=0 [pam_yubico.c:parse_cfg(729)] verbose_otp=0 [pam_yubico.c:parse_cfg(730)] try_first_pass=0 [pam_yubico.c:parse_cfg(731)] use_first_pass=0 [pam_yubico.c:parse_cfg(732)] authfile=(null) [pam_yubico.c:parse_cfg(733)] ldapserver=(null) [pam_yubico.c:parse_cfg(734)] ldap_uri=(null) [pam_yubico.c:parse_cfg(735)] ldapdn=(null) [pam_yubico.c:parse_cfg(736)] user_attr=(null) [pam_yubico.c:parse_cfg(737)] yubi_attr=(null) [pam_yubico.c:parse_cfg(738)] yubi_attr_prefix=(null) [pam_yubico.c:parse_cfg(739)] url=(null) [pam_yubico.c:parse_cfg(740)] capath=(null) [pam_yubico.c:parse_cfg(741)] token_id_length=12 [pam_yubico.c:parse_cfg(742)] mode=chresp [pam_yubico.c:parse_cfg(743)] chalresp_path=(null) [pam_yubico.c:pam_sm_authenticate(775)] get user returned: jas [pam_yubico.c:do_challenge_response(493)] Loading challenge from file /home/jas/.yubico/challenge-1077187 [util.c:load_chalresp_state(269)] Challenge: 23001a190724abf46c8022b008ccb65673dd634ecb150613771ec87f37850284d80dd5f8c8e56affb6da2e952b16682160e7f3ac4f816b64126bd9556e5be1, response: 63d4a679ed15335ffd4253e7609963bcdb0834d4, slot: 2 [pam_yubico.c:do_challenge_response(566)] Got the expected response, generating new challenge (63 bytes). [pam_yubico.c:do_challenge_response(629)] Challenge-response success!
and if there is no YubiKey in the machine it will look like this:
[pam_yubico.c:parse_cfg(721)] called. [pam_yubico.c:parse_cfg(722)] flags 32768 argc 2 [pam_yubico.c:parse_cfg(724)] argv[0]=mode=challenge-response [pam_yubico.c:parse_cfg(724)] argv[1]=debug [pam_yubico.c:parse_cfg(725)] id=-1 [pam_yubico.c:parse_cfg(726)] key=(null) [pam_yubico.c:parse_cfg(727)] debug=1 [pam_yubico.c:parse_cfg(728)] alwaysok=0 [pam_yubico.c:parse_cfg(729)] verbose_otp=0 [pam_yubico.c:parse_cfg(730)] try_first_pass=0 [pam_yubico.c:parse_cfg(731)] use_first_pass=0 [pam_yubico.c:parse_cfg(732)] authfile=(null) [pam_yubico.c:parse_cfg(733)] ldapserver=(null) [pam_yubico.c:parse_cfg(734)] ldap_uri=(null) [pam_yubico.c:parse_cfg(735)] ldapdn=(null) [pam_yubico.c:parse_cfg(736)] user_attr=(null) [pam_yubico.c:parse_cfg(737)] yubi_attr=(null) [pam_yubico.c:parse_cfg(738)] yubi_attr_prefix=(null) [pam_yubico.c:parse_cfg(739)] url=(null) [pam_yubico.c:parse_cfg(740)] capath=(null) [pam_yubico.c:parse_cfg(741)] token_id_length=12 [pam_yubico.c:parse_cfg(742)] mode=chresp [pam_yubico.c:parse_cfg(743)] chalresp_path=(null) [pam_yubico.c:pam_sm_authenticate(775)] get user returned: jas [pam_yubico.c:do_challenge_response(478)] Failed initializing YubiKey [pam_yubico.c:do_challenge_response(640)] YubiKey core error: no YubiKey present