YubiKey, for multi-factor authentication on Linux.

YubiKey Authentication

YubiKey

A YubiKey is a small hardware authentication device that supports PKCS #11, OTP or One-Time Password, and U2F or Universal 2nd Factor with the FIDO/FIDO2 protocols.

Several models are available, for US$ 20–70. They plug into USB ports, either the classic USB-A like the one shown above or the newer USB-C, and some can communicate with NFC or Near-Field Communications over low-power HF radio.

A YubiKey can provide a second mechanism for multi-factor authentication. A password is something you know, while a device like this is something you have.

YubiKey with
pam_pkcs11.so
YubiKey with
pam_u2f.so
A YubiKey can function in various ways, depending on which authentication libraries we use. A YubiKey contains a PIV application which operates with the pam_pkcs11.so authentication module, and a FIDO U2F application which operates with the pam_u2f.so authentication module.

This page explains what a YubiKey does and how to test and configure it with a command-line tool. Other pages explain the specific PAM configuration details.

YubiKey authentication device.

Public Key Cryptography Standards

RSA Security published a series of Public-Key Cryptography Standard or PKCS documents, starting in the early 1990s. PKCS #1 through #15 are mentioned, although #13 and #14 were apparently abandoned before any documents were written, #2 and #4 were merged into #1, and #6 is obsolete as it defined extensions to the old X.509 certification format (from 1988) that were included in X.509v3. The most interesting ones include:

Interacting with a YubiKey

EPEL is Extra Packages for Enterprise Linux, a large collection of software included in the Fedora project but not included with the Enterprise distributions. Linux Package Management

The yubikey-manager package contains only one file, /usr/bin/ykman, an 11-line Python script, which needs the python36-yubikey-manager package. Debian and Ubuntu software repositories include it, with Red Hat and Oracle you need to add the EPEL repository.

No documentation is included with the packages, from either the EPEL repositories used with Red Hat and Oracle Linux, or the Debian repositories. Yubico has the missing ykman manual, although it doesn't completely agree with the behavior of the latest available packages available in the EPEL and Debian repositories.

YubiKey Applications

I can ask the device what it is and which applications it supports:

$ lsusb
Bus 001 Device 003: ID 1050:0407 Yubico.com Yubikey 4/5 OTP+U2F+CCID
Bus 001 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
$ ykman list
YubiKey 4 [OTP+FIDO+CCID] Serial: 9140275
$ ykman info
Device type: YubiKey 4
Serial number: 9140275
Firmware version: 4.3.7
Enabled USB interfaces: OTP+FIDO+CCID

Applications
OTP     	Enabled
FIDO U2F	Enabled
OpenPGP 	Enabled
PIV     	Enabled
OATH    	Enabled
FIDO2   	Not available 
YubiKey authentication device plugged into a laptop.

OTP or One-Time Password

The OTP or One-Time Password application outputs a 44-character string. The device acts as though it were a keyboard. The first 12 characters of the output remain constant, the Public ID of the YubiKey device.

The remaining 32 characters contain an encrypted one-time passcode. That passcode is generated by first concatenating five fields:

Bytes Value
6 Private ID field
2 Number of times plugged in
3 Timestamp: set to a random value at power-up, incremented at 8 Hz.
1 Number of button presses since last plugged in
2 Random number

That 32-byte string is encrypted with AES using a 128-bit key stored in the device. Here is the result of plugging in a device and pressing the button 10 times, ccccccjnijee is its OTP YubiKey ID.

ccccccjnijeeujejinuftbhrchjcllfnhubelidllvuk
ccccccjnijeeujrdcghvjtdfdbrtcbggjktlnflrvckj
ccccccjnijeeduubftfhhennldjcjcbvikirlljhhkbn
ccccccjnijeetftbhktvulkntlhbeuedvhdvnrurgcje
ccccccjnijeenenrfvbvbgvhtittkrtlkdbvkcilinvf
ccccccjnijeeendiiibuurtrrnhbrngvbgelckelhenf
ccccccjnijeefcrrdejhitlttchgukuuiuhninuglncr
ccccccjnijeeufhjnnviggrrtbhckcdgrhvcbcvbtcdk
ccccccjnijeegfnduhgeelbbcuhkfindhkjturddcleg
ccccccjnijeehehjjbbjgvedvhbtrbbvnjlfkgretktn 

Yubico uses its own "Modhex" or "Modified Hexadecimal" encoding designed to be portable across a wide range of keyboard layouts and encodings. The YubiKey acts like a keyboard plugged into a USB port. USB keyboards send scan codes, not the actual characters, and it's up to the terminal emulator and the locale setting to turn scan codes into characters. A US keyboard with a QWERTY layout, a French one with AZERTY, or a German one with QWERTZ would agree on the Modhex coding.

Hex 0 1 2 3 4 5 6 7 8 9 a b c d e f
Modhex c b d e f g h i j k l n r t u v

And so the Yubico Modhex ccccccjnijee corresponds to 0x0000008b7833 or 9140275 in base 10. Yes, that's the serial number.

$ ykman list
YubiKey 4 [OTP+FIDO+CCID] Serial: 9140275 

A good cipher like AES has a diffusion property that spreads the first 6 bytes of the cleartext throughout the ciphertext, and the first 6 bytes of the ciphertext contain substituted bits from throughout the cleartext. The first 6 bytes of ciphertext do not correspond to the first 6 bytes of cleartext.

A Yubico Server could use the ID to look up the AES key programmed into the device at the factory, and then decrypt the remaining 32 bytes to verify the private ID field, the first 6 bytes. It could then use the counters of times plugged in and button presses since then to verify that it's a new event, foiling a replay attack.

And so, you could use the OTP functionality in two ways. First, a weak or naive way which only looks at the cleartext 12-byte initial output. "Does the device output begin with ccccccjnijee?" The second way would decrypt the remaining 32 bytes of the output and check the Private ID. That would require an attacker to extract the Private ID and embedded 128-bit AES key, in order to generate properly encrypted 32-byte passcodes containing the Private ID and an incrementing counter value. Of course, the stronger second method would also require the server to know how to decrypt the passcode! You could pay Yubico for the use of a server with that capability. Or, you can generate your own OTP identity and add it to the device, and then use suitable software to communicate with the device and then decrypt and analyze its output.

There are two "slots", two storage locations, for OTP identities. The first is programmed at the factory, with a private device ID and 128-bit AES key known only to the factory. The second slot is available for your use.

$ ykman otp info
Slot 1: programmed
Slot 2: empty 

To program your own OTP credentials into slot 2 using the device serial number as its public ID, 0x0123456789ab as its 12-byte private ID, and 0xfeedfacedeadbeeffeedfacedeadbeef as the 128-bit AES key:

$ ykman otp yubiotp --serial-public-id \
	--private-id 0123456789ab \
	--key feedfacedeadbeeffeedfacedeadbeef 2
Using YubiKey serial as public ID: vvccccjnijee
Program an OTP credential in slot 2? [y/N]: y
$ ykman otp info
Slot 1: programmed
Slot 2: programmed 

While it reported "Using YubiKey serial as public ID", it used vvccccjnijee instead of ccccccjnijee, so 0xff00008b7833 instead of 0x0000008b7833.

As we'll see, that's extremely helpful, essential even, for distinguishing between your locally created identity and the factory-installed one. The one starting 0x00 was installed at the factory, the one starting 0xFF or with your selected value is one you created.

Good to know. Next time 'll explicitly set a public ID I will recognize.

You could instead use --public-id followed by an arbitrary 12-character Modhex string. There are at least 26 choices in the form of words or names, these are known to Debian Linux:

$ egrep -i '^[cbdefghijklnrtuv]{12}$' /usr/share/dict/words
belligerence
bullfighting
centrifuging
enlightening
firefighting
freethinking
genuflecting
highlighting
indifference
intelligence
intelligible
interdicting
interference
interjecting
interlinking
jitterbugged
nightclubbed
rubbernecked
underbidding
undercurrent
undercutting
underfeeding
unfriendlier
unidentified

That seems arbitrary, jitterbugged but not jitterbugger, the act but not the actor. Mint Linux adds the names Breckenridge and Ferlinghetti to that list. Red Hat offers an additional 197 supposed words, including dubious ones like becudgelling, eleventeenth, digitinerved, fiddledeedee, hedenbergite, killeekillee, tenthredinid, and unthundering, plus downright Turkish looking strings like beglerbeglik.

Now we can swap the contents of the two slots, so our new identity will be used to generate the output:

$ ykman otp swap
Swap the two slots of the YubiKey? [y/N]: y
Swapping slots...
$ cat | tee /tmp/otp-output
vvccccjnijeeeetvrdcdttvrljkltttitdlvjfkdfhcn   # pressing the button 10 times...
vvccccjnijeehcdvkbhtnebergflbjcucdullelvdibe
vvccccjnijeejgvirlbhvrjkevvvhtbdgbvutngdfdeu
vvccccjnijeevhblehebehitnltgbuhtrbdubldrfbjc
vvccccjnijeeljgclvbtkihjkkdcctneciujivrvlfif
vvccccjnijeetjtdcugerljcrjkdekhjenvlbfbttnvu
vvccccjnijeediccirftlfkukngbjbgikhugidnhnjnc
vvccccjnijeehrjdhbfnibbukulekktgkiviuccvlldf
vvccccjnijeeueielngvddjllgkjivhittekchdbctuj
vvccccjnijeeuucelnvhlcfvurnclirrklggfhbenuvf
^C 

That was an interesting experiment, but let's get the OTP functionality back to the original so we don't lose track of the factory identity. To be safe, I'll press the button and make sure we're back to the original ccccccjnijee identity in slot 1. Then I'll delete the test identity in slot 2.

$ ykman otp swap
Swap the two slots of the YubiKey? [y/N]: y
Swapping slots...
$ ccccccjnijeerdulibltfekbigunvikcfenkrltbicht
ccccccjnijeerdulibltfekbigunvikcfenkrltbicht: command not found
$ ykman otp delete 2
Do you really want to delete the configuration of slot 2? [y/N]: y
Deleting the configuration of slot 2...
$ ykman otp info
Slot 1: programmed
Slot 2: empty 

FIDO U2F

FIDO U2F is enabled on the device:

$ ykman list
YubiKey 4 [OTP+FIDO+CCID] Serial: 9140275
$ ykman info
Device type: YubiKey 4
Serial number: 9140275
Firmware version: 4.3.7
Enabled USB interfaces: OTP+FIDO+CCID

Applications
OTP     	Enabled
FIDO U2F	Enabled
OpenPGP 	Enabled
PIV     	Enabled
OATH    	Enabled
FIDO2   	Not available 

However, it doesn't work with the ykman command. It's as if something was missing but I'm not being told just what that is. As we see above, this device has FIDO but not FIDO2. I would expect the following fido2 command to fail, but the fido seems to try to do FIDO2 instead:

$ ykman fido -h
Usage: ykman fido [OPTIONS] COMMAND [ARGS]...

  Manage FIDO applications.

  Examples:

    Reset the FIDO (FIDO2 and U2F) applications:
    $ ykman fido reset

    Change the FIDO2 PIN from 123456 to 654321:
    $ ykman fido set-pin --pin 123456 --new-pin 654321

Options:
  -h, --help  Show this message and exit.

Commands:
  info     Display status of FIDO2 application.
  reset    Reset all FIDO applications.
  set-pin  Set or change the PIN code.
  unlock   Verify U2F PIN for YubiKey FIPS.
$ ykman fido info
Usage: ykman fido [OPTIONS] COMMAND [ARGS]...
Try "ykman fido -h" for help.

Error: Failed to load FIDO 2 Application.
$ ykman fido2 info
Usage: ykman [OPTIONS] COMMAND [ARGS]...
Try "ykman -h" for help.

Error: No such command "fido2".
$ ykman u2f info
Usage: ykman [OPTIONS] COMMAND [ARGS]...
Try "ykman -h" for help.

Error: No such command "u2f".

There has been a yubikey-personalization-gui tool, as shown below.

YubiKey Linux software yubikey-personalization-gui.

However, it offers no FIDO or FIDO2 controls. And, I notice that while I installed this package from the EPEL repository in the spring of 2021, the package reports a Build Date of Jan 17 2018, and the panel displays "Copyright © 2011-2016 Yubico". The company says that the project is no longer maintained, and we should install the graphical yubikey-manager-qt or the command-line yubikey-manager. They recommend some steps for installing those from their on-line repository, but their repository contains no data.

But the FIDO U2F function does work. See my pam_u2f.so page for the details.

PIV Standards and Ciphers and Slots

YubiKey 4 and 5 series support the PIV or Personal Identity Verification interface specified in NIST SP 800-73. This supports RSA or ECC (Elliptic-Curve Cryptography) sign and decrypt operations using a private key stored on the device, through common interfaces like PKCS #11.

The PIV application has its own slots, individual key storage locations with very arbitrary names or addresses. Key slots 9A, 9C, 9D, and 9E can hold RSA or ECC asymmetric keys. Key slot 9B can hold a Triple-DES key used for PIV management.

Access to the keys can be controlled by user knowledge of a PIN. Depending on the slot, the PIN might be needed for every single operation, once to begin a series of operations, or not at all.

Key slots 9A, 9C, 9D, and 9E can hold RSA 1024-bit, RSA 2048-bit, or ECC secp256r1 (also known as NIST P-256) keys. NSA describes the CNSA or Commercial National Security Algorithm Suite as protecting US Government data up to TOP SECRET using:

For PIV authentication using slot 9A, you store a PFX (or PKCS #12) file. That file combines the user's private key and their public key in the form of a certificate signed by a trusted CA or Certificate Authority. You create and operate that CA. The YubiKey will require the device PIN to begin any sequence of operations using this slot, as the PFX file contains their private key.

The details of the user key pair don't really matter. It could be RSA of any length, or ECC with the prime256v1 (also called NIST P-256), secp256k1, secp384r1 (P-384), or secp521r1 (P-521) curves. Or, with a more capable version of OpenSSL, any elliptic curve listed in the output of:

$ openssl ecparam -list_curves

What matters is that the certificate must name the user as the CN or Canonical Name, and it must be signed by the CA using either RSA (with a 1024 or 2048-bit key) or ECC secp256r1 (that is, P-256).

Here is an example of a YubiKey set up for PIV authentication from today through the following year. The certificate was signed with an ECC P-256 key.

$ ykman piv info
PIV version: 4.3.7
PIN tries remaining: 3
CHUID:	3019d4e739da739ced39ce739d836858210842108421c84210c3eb3410cfd6d8b0604959b1871b5ab6b2ffc34a350832303330303130313e00fe00
CCC: 	f015a000000116ff0217b5e9fa5cc2252ff4070b8ac930f10121f20121f300f40100f50110f600f700fa00fb00fc00fd00fe00
Slot 9a:
	Algorithm:	ECCP256
	Subject CN:	cromwell
	Issuer CN:	pki.cromwell-intl.com
	Serial:		16865202850031608285
	Fingerprint:	6f27531482794e9f2dc79025046e401ee330bffd43fbf579ccc6bcb2f03c2198
	Not before:	2023-06-05 16:18:38
	Not after:	2024-06-05 16:18:38

Now you can configure YubiKey authentication with PAM modules pam_u2f.so or pam_pkcs11.so.