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_yubico.so
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
challenge-response application which operates with the
pam_yubico.so
authentication module,
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.
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:
- PKCS #1 — Defines the RSA asymmetric cipher — the mathematics, the encoding format of public and private keys, and the algorithms and encoding and padding for encryption, decryption, and the creation and verification of digital signatures.
- PKCS #3 — Diffie–Hellman Key Agreement, to securely establish a shared secret key over an insecure communications channel.
- PKCS #5 — Password-based Encryption Standard: now see RFC 8018 and PBKDF2, used to (hopefully) create a symmetric encryption key with adequate entropy based upon a password or pass phrase chosen and remembered by a person.
- PKCS #7 — Cryptographic Message Syntax Standard, which formed the basis for S/MIME, for signing and/or encrypting messages within a PKI or Public Key Infrastructure.
- PKCS #11 — Cryptographic Token Interface, an API or application programming interface defining a generic way for software to interact with cryptographic tokens. It names it "Cryptoki" as in "cryptographic token interface".
-
PKCS #12 — Personal Information Exchange Syntax
Standard, a file format used to store private keys
along with corresponding public key certificates,
protected by a password-based symmetric key.
Commonly abbreviated PFX due to the ancient
Microsoft 3-letter filename extension standard,
as in
*.pfx
. See RFC 7292 for the details.
Interacting with a YubiKey
The yubikey-manager
package contains only
one file, /usr/bin/ykman
, an 11-line Python script,
which needs some Python packages:
python3-click
python3-fido2
*
python3-pyOpenSSL
python3-pyscard
*
python3-pyusb
python3-yubikey-manager
*
* = in the EPEL repository
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 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 002: ID 1050:0407 Yubico.com Yubikey 4/5 OTP+U2F+CCID
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
$ ykman list
YubiKey 5 NFC [OTP+FIDO+CCID] Serial: 23981622
$ ykman info
Device type: YubiKey 5 NFC
Serial number: 23981622
Firmware version: 5.4.3
Form factor: Keychain (USB-A)
Enabled USB interfaces: OTP+FIDO+CCID
NFC interface is enabled.
Applications USB NFC
OTP Enabled Enabled
FIDO U2F Enabled Enabled
OpenPGP Enabled Enabled
PIV Enabled Enabled
OATH Enabled Enabled
FIDO2 Enabled Enabled
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, cccccbhtuueh
is its
OTP YubiKey ID.
cccccbhtuuehgkncvtutirgivddcgdntfrrcrctlcfeh cccccbhtuuehlrlfhnltnuifkntehluiuvfnfbkdgfbi cccccbhtuuehbvkfvujctfhhnigidhuflbkhihdhufbl cccccbhtuuehngvhhltdvdvrvththirbjkrertkkhide cccccbhtuuehnejrglegbldedgtdblnttuchrkiicddu cccccbhtuuehkfthrvifcedtuulhcuvkvrcchtcerhdv cccccbhtuuehnvgregnjfvnrngfikgbvvdgtitnnujbi cccccbhtuuehbrnulkivvujcvlggblftucikcrlvngbb cccccbhtuuehkluduvucefinbtnnuikiggkeiegkhfnc cccccbhtuuehvetehnlbijrkkeclulnennlkihvvbjcj
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 cccccbhtuueh
corresponds to 0x0000008b7833
0x0000016dee36
or 23981622 in base 10.
Yes, that's the serial number.
$ ykman list YubiKey 5 NFC [OTP+FIDO+CCID] Serial: 23981622
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: vvcccbhtuueh 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 vvcccbhtuueh
instead of
cccccbhtuueh
,
so 0xff00016dee36
instead of 0x0000016dee36
.
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 I can 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...
vvcccbhtuuehhcdvkbhtnebergflbjcucdullelvdibe
vvcccbhtuuehjgvirlbhvrjkevvvhtbdgbvutngdfdeu
vvcccbhtuuehvhblehebehitnltgbuhtrbdubldrfbjc
vvcccbhtuuehljgclvbtkihjkkdcctneciujivrvlfif
vvcccbhtuuehtjtdcugerljcrjkdekhjenvlbfbttnvu
vvcccbhtuuehdiccirftlfkukngbjbgikhugidnhnjnc
vvcccbhtuuehhrjdhbfnibbukulekktgkiviuccvlldf
vvcccbhtuuehueielngvddjllgkjivhittekchdbctuj
vvcccbhtuuehuucelnvhlcfvurnclirrklggfhbenuvf
^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... $ cccccbhtuuehrdulibltfekbigunvikcfenkrltbicht cccccbhtuuehrdulibltfekbigunvikcfenkrltbicht: 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 5 NFC [OTP+FIDO+CCID] Serial: 23981622 $ ykman info Device type: YubiKey 5 NFC Serial number: 23981622 Firmware version: 5.4.3 Form factor: Keychain (USB-A) Enabled USB interfaces: OTP+FIDO+CCID NFC interface is enabled. Applications USB NFC OTP Enabled Enabled FIDO U2F Enabled Enabled OpenPGP Enabled Enabled PIV Enabled Enabled OATH Enabled Enabled FIDO2 Enabled Enabled $ 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: delete Delete a resident credential. 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 PIN is not set. $ ykman fido set-pin --new-pin 1234 $ ykman fido info PIN is set, with 8 tries left. $ ykman fido2 info Usage: ykman [OPTIONS] COMMAND [ARGS]... Error: No such command "fido2". $ ykman u2f info Usage: ykman [OPTIONS] COMMAND [ARGS]... Error: No such command "u2f".
There has been a yubikey-personalization-gui
tool, as shown below.
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 devices 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.
- Slot 9A: PIV authentication of the device and user. The device PIN is needed to begin any sequence of private key operations.
- Slot 9C: Digital signature for signing documents and other files. The device PIN is needed for every signing operation.
- Slot 9D: Key management for encryption of files or email message contents. The device PIN is needed to begin any sequence of private key operations.
- Slot 9E: Card authentication for physical access as with PIV-enabled door locks. The device PIN is not needed.
- Slots 82-95: Retired key management slots, intended for previously used Key Management keys for decrypting earlier encrypted documents or emails, still available for use.
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. According to Yubico, with firmware v5.2 and later you can store RSA plus ECC with curves secp256r1, secp256k1, secp384r1, secp521r1, brainpoolP256r1, brainpoolP384r1, brainpoolP512r1, and curve25519 (x25519 for decipher only, ed25519 for sign/auth only). In 2020, NSA described the CNSA or Commercial National Security Algorithm Suite as protecting US Government data up to TOP SECRET using:
- AES symmetric cipher with 256-bit keys as per FIPS Pub 197
- ECDH or Elliptic Curve Diffie-Hellman Key Exchange using Curve P-384 as per NIST SP 800-56-A
- ECDSA or Elliptic Curve Digital Signature Algorithm using Curve P-384 as per FIPS Pub 186-5
- SHA-2-384 hash function as per FIPS Pub 180-4
- DH or Diffie-Hellman Key Exchange with a minimum 3072-bit modulus as per IETF RFC 3526
- RSA asymmetric cipher for key establishment and digital signatures with minimum 3072-bit modulus as per NIST SP 800-56B
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 on which PIV authentication has not yet been configured.
$ ykman piv info PIV version: 5.4.3 PIN tries remaining: 3 CHUID: No data available. CCC: No data available.
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: 2025-01-08 09:58:54 Not after: 2026-01-08 09:58:54
Now you can configure YubiKey authentication with PAM modules
pam_yubico.so
or
pam_u2f.so
or
pam_pkcs11.so
.
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