A YubiKey is an ingenious hardware authentication token that looks like a very small USB memory stick, but actually acts as a type of USB keyboard. With the touch of a button, a YubiKey can send a time-variant, secure passcode as if it was typed in from a keyboard. Since USB keyboards are supported by most computers the YubiKey works on the majority of platforms and browsers without the need for any client software.
The YubiKey was invented in 2006 by Stina and Jakob Ehrensvärd and first sold to the public in 2008. Since then it has gone through a number of product iterations. The current version is 2.2. Competitors to YubiKey include SweKey and UniKey.
A YubiKey weighs about 2.5 grams and is made from plastic. All YubiKeys are marked with a unique serial number and 2D bar code, enabling a YubiKey to be easily matched with a specific user, using a bar code scanner or smart phone camera. A YubiKey is not firmware upgradable for security reasons.
The single button on a YubiKey provides a one time passcode (OTP) with each touch of the button which can be used to authenticate a user. Each OTP is one AES block, and is encrypted in Electronic Code Book (ECB) mode. A YubiKey can be programmed to have two independent and separate configurations, including any two of the following:
- 44 character one time passcode. This is the default configuration.
- OATH-HOTP 6 or 8 digit one time password.
- 1-38 character static pass code.
- Challenge-response functionality using client software. Yubico OTP and HMAC-SHA1 is supported.
The above configurations apply to the YubiKey v2.2 which was introduced in September 2010. I shall, however, only be discussing the first configuration, i.e. OTP, in this post as that is what Fedora 14 uses.
So how does a YubiKey OTP work? The basic concept can be described as follows:
- A Yubikey is inserted into a USB port.
- The computer detects it as an external USB HID keyboard.
- The user touches the OTP generation button.
- A unique code is formed from various internally stored and calculated fields (see below.)
- This code is encrypted with a 128-bit AES key
- The encrypted code is converted to a series of characters that are outputted as keystrokes via the keyboard port
The unique code consists of the following fields which are in little-endian format:
- A 48-bit private identity field to verify the decrypted result to a non-published identity,
- A 8-bit volatile counter that is incremented by one each time a code is generated and reset at power-up,
- A 16-bit non-volatile counter that is incremented by one for each power-up event,
- A 24-bit timestamp increased at a rate of approximately 8Hz,
- A 16-bit random number,
- A 16-bit CRC16 checksum.
According to Yubico, the Swedish company behind the YubiKey, a YubiKey generates a unique 128-bit code each time the OTP button is touched and there is no time window during which two authentication codes are equal. After encryption, the authentication code is converted to a special data encoding format known as modhex.
Modhex is an encoding designed to cope with various keyboard layouts. A USB keyboard emits scan codes rather than a character when a key is pressed. Different keyboard layouts are used in different locales. Modhex only uses specific characters that do not create any ambiguities. Modhex coding packs four bits of information in each keystroke/character. Thus a 128-bit OTP string requires a 32 character string. You and/or an application see 44 characters because a 12 character modhex client ID is prepended to the 32 character string.
Verification of an OTP can be conceptually described as follows:
- The received OTP string is converted back to a byte string.
- The byte string is decrypted using the same (symmetric) 128-bit AES key.
- The checksum is verified. If not valid, the OTP is rejected.
- Additional fields are verified. If not valid, the OTP is rejected.
- The non-volatile counter is compared with the previously received value.
- If lower than or equal, the received OTP is rejected as a replay.
- Otherwise the received value is stored and the OTP is accepted as valid.
From this brief description it should be clear that the security of a Yubikey depends on the verification device keeping track of the last sequence number received from a particular device.
Recently the Fedora Project enabled authentication using a YubiKey to enhance access control to critical hosts. However, that is not what this post is about. Instead, this post describes how to enhance user authorization on Fedora 14 platforms by adding support for two-factor authentication using a YubiKey OTP.
A Yubico-developed PAM module called yubico_pam is available that allows authentication of users with a YubiKey on systems that can contact an authentication server. Yubico uses the term validation server and this is the term used in the remainder of this post. The validation server can either be an inhouse server or provided by a contracted third party or you can simply use the free validation service provided by Yubico using a RADIUS server.
A reasonably fast connection to a validation server is required or proper authentication will not occur. There is no support for a disconnected mode of operation in with this particular PAM module. If you want to use a YubiKey on systems that are not networked, an alternative PAM module is available from Securix. With this module, the required AES keys are managed by a utility, ykpasswd and stored in a local encrypted database. Note, however, that the current release only supports single factor sign-in. If you want to implement your own YubiKey validation server, Yubico provides PHP, Java and other reference implementations.
Install the pam_yubico and ykclient packages. Both are available in the default Fedora repositories.
# rpm -ql pam_yubico /lib64/security/pam_yubico.so /usr/share/doc/pam_yubico-2.1 /usr/share/doc/pam_yubico-2.1/COPYING /usr/share/doc/pam_yubico-2.1/ChangeLog /usr/share/doc/pam_yubico-2.1/NEWS /usr/share/doc/pam_yubico-2.1/README # rpm -ql ykclient /usr/bin/ykclient /usr/lib64/libykclient.so.3 /usr/lib64/libykclient.so.3.1.0 /usr/share/doc/ykclient-2.3 /usr/share/doc/ykclient-2.3/AUTHORS /usr/share/doc/ykclient-2.3/COPYING /usr/share/doc/ykclient-2.3/NEWS /usr/share/doc/ykclient-2.3/README
Curl is also required and will be installed if not already installed. Note the lack of man pages for both pam-yubico and ykclient. The trend seems to be towards providing documentation in /usr/share/doc rather than as traditional man pages. I believe that is is an unfortunate trend in that it makes retrieving information about a command or module more difficult than it needs to be.
The version of pam_yubico (2.1) in the Fedora repositories is quite old (March 2009). If you want to update it with either the 2.4 or 2.5 version, source tarballs can be found at code.google.com. Note that the default build configuration script fails to find /usr/lib64/libykclient.so on 64-bit platforms. I did not check if a similar problem occurs on a 32-bit Fedora platform.
Next edit the PAM configuration file /etc/pam.d/gdm-password. Here is the default contents of this file for Fedora 14:
auth [success=done ignore=ignore default=bad] pam_selinux_permit.so auth substack password-auth auth required pam_succeed_if.so user != root quiet auth optional pam_gnome_keyring.so account required pam_nologin.so account include password-auth password include password-auth session required pam_selinux.so close session required pam_loginuid.so session optional pam_console.so session required pam_selinux.so open session optional pam_keyinit.so force revoke session required pam_namespace.so session optional pam_gnome_keyring.so auto_start session include password-auth
For two-factor authentication, add
auth sufficient pam_yubico.so id=16 authfile=/etc/yubikey_mappings
immediately after the second line i.e.
auth substack password-auth
If, instead, you wish to use an OTC instead of a password (which I do not recommend, see below), replace
auth substack password-auth
auth sufficient pam_yubico.so id=16 authfile=/etc/yubikey_mappings
While a Yubikey can be used in one-factor authentication, it is really intended to be used in two-factor authentication. A Yubikey should be used with a second factor, such as a password or a PIN, to prevent unauthorized access if a YubiKey is lost or stolen.
In the changes to gdm_password PAM configuration file described above, I set the pam_yubico ID parameter to 16. This seems to be a default value which always works. If you want to use your own ID, go to Get Yubico API Key. The new ID will work with the pam_yubico module although I am not sure what value it adds.
Note also that the pam_yubico module can take a number of configuration parameters including:
authfile Indicate the location of the file that holds the mappings of yubikey token ids to user names. id Indicate your client identity, debug Enable debugging output to stdout, alwaysok All authentication attempts succeed try_first_pass Before prompting the user for their password, the module first tries the previous stacked module´s password in case that satisfies this module as well. use_first_pass The argument use_first_pass forces the module to use a previous stacked modules password and will never prompt the user - if no password is available or the password is not appropriate, the user will be denied access. url Specify the URL to use for authentication. The default is "http://api.yubico.com/wsapi/verify?id=%d&otp=%s" ldapserver Specifiy the ldap server host (default ldap port is used) ldapdn Specify the dn where the users are stored (eg: ou=users,dc=domain,dc=com) user_attr Specify the attribute used to store usernames (eg:cn) yubi_attr Specify the attribute used to store the yubikey id
Next, a mapping must be made between the YubiKey token ID (see below) and the user ID it is associated with. There are two ways to do this, either centrally in one file, or individually where users can create the mapping in their home directories. If a system authorization mapping file is being used, user home directory mappings will not be used and the opposite applies if user home directory mappings are being used, the system authorization mappings file will not be used.
Assuming your system mapping file is /etc/yubikey_mappings, you add a new user to the file using colon syntax similar to that used for /etc/passwd i.e
If you have more than one YubiKey, additional token IDs are separated by colons.
For example, suppose the user ID is jce and their YubiKey token ID is vvgefrdffktn, the entry for this user in /etc/yubikey_mappings would be:
If you do not want to have a system mapping file, create a $HOME/.yubico/authorized_yubikeys file to map the association between a user and their YubiKey(s). The syntax is the same as for the system-wide mapping file – so for user jce with one YubiKey whose token ID is vvgefrdffktn this file would contain the following entry:
This file must have only one line.
There are a number of ways of determining a YubiKey token ID. The token ID is always the first 12 characters of any OTP. Alternatively, you can retrieve a YubiKey token ID using the Yubico Modhex_Calculator by entering an OTP in the String textbox. The modhex encoded string that is displayed after you enter the OTP is your YubiKey token ID.
That is all that is required to set up your YubiKey for use with GNOME Desktop Manager on Fedora 14. When you next log back in your system you should either be prompted to enter both your password and an OTP or both depending on how you configured the gdm-password PAM configuration file.
If you want to modify your GNOME screensaver, to also require two-factor authentication using an OTP, modify /etc/pam.d/gnome-screensaver as follows:
session include system-auth
auth substack password-auth
auth sufficient pam_yubico.so id=16 debug authfile=/etc/yubikey_mappings
auth optional pam_gnome_keyring.so
auth required pam_deny.so
account include system-auth
If you want to have your system invoke a locked screensaver when a YubiKey is removed, have a look at this Yubico forum post. I have not tested the code so I have no idea whether it works on Fedora 14 or not.
Modifying the /etc/pam.d/login configuration file to provide two-factor authentication for virtual console logins appears not to work at present. Asterisks to represent the OTP character string are not outputted to the console and the connection to the Yubico validation service fails.
What can go wrong? Unless you set up your own validation server, you are dependent on a reliable network connection to the Yubico validation server and on the correct and timely operation of that validation server. If there is a significant time offset between the validation server and your system, validation may not occur. For this reason you should synchronize your system time with a time server.
Be careful not to touch the OTP button for more than a 1.5 seconds if you have more than one configuration as the OTP from the second configuration is sent instead of the first configuration if a long press (2.5 – 5 seconds) is detected.
The green indicator light on the YubiKey can provide diagnostic information. A steady green light means that the Yubikey is ready to generate an OTP whereas a rapidly flashing light signals some form of error condition. Yubico also provides a Demonstration Webpage where you can test your YubiKey.
If you want to obtain debugging information from the pam_yubico module, ensure that the debug parameter is added to the pan_yubico entry in the appropriate PAM configuration file(s), and set up the debugging output log file as follows:
chmod go+w /var/run/pam-debug.log
A useful utility for testing your YubiKey is /usr/bin/ykclient.
$ /usr/bin/ykclient Usage: /usr/bin/ykclient
CLIENT_ID: your client id integer YUBIKEY_OTP: One-time password generated by yubikey $ /usr/bin/ykclient 16 vvegfrdffktnigcnldderljuncvngehnjiihhrggceed Input: client id: 16 token: vvegfrdffktnigcnldderljuncvngehnjiihhrggceed Verification output (0): Success $
Well, this post should contain all the information you need to get YubiKey authentication working on Fedora 14. Remember to always keep a console open as root when you are testing changes to user authentication. It is easy to get locked out of your system when you are experimenting with PAM configurations!
Please let me know if I have left something important out or provided incorrect information and I will update this post.