Universal 2nd Factor

Universal 2nd Factor (U2F)
is an open standard that strengthens and simplifies two-factor authentication (2FA) using specialized USB or NFC devices based on similar security technology found in smart cards.
While initially developed by Google and Yubico, with contribution from NXP Semiconductors, the standard is now hosted by the FIDO Alliance.
For all articles on U2F and U2F-devices see:
Category:Universal 2nd Factor
.
WebAuthn
is a more recent standard.
Authentication for websites
U2F is supported by major sites like Google, Facebook, Twitter, or GitHub. Check out
2fa.directory
or
dongleauth.com
to find other websites and links to setup documentation. For all browsers which support it, likely the only action required is to install
libfido2
. Yubico offers a
demo page
for testing.
Firefox
Firefox/Tweaks#Fido U2F authentication
Chromium/Chrome
Chromium/Tips and tricks#U2F authentication
Authentication for user sessions
Yubico, the company creating the YubiKey, develops an U2F
PAM
module. It can be used to act as a second factor during login or replace the need for a password entirely.
Note
Despite the mentions of Yubico/YubiKey in this document,
pam-u2f
should also support any U2F and/or FIDO2 compliant keys.
Installing the PAM module
The module is part of the package
pam-u2f
.
Adding a key
Note
The folder name below is the default location. It can be changed for
single user
implementations by moving the file to your preferred directory and appending
authfile=/path/to/u2f_keys
to the end of the line for pam_u2f.so. This is also useful if you wish to move
u2f_keys
to a protected part of the file-system. For multi-user implementations use a central mapping file as explained in the
official documentation of pam-u2f
.
Keys need to be added with the tool
pamu2fcfg
:
$ mkdir ~/.config/Yubico
$ pamu2fcfg -i pam://
hostname
> ~/.config/Yubico/u2f_keys
After entering your PIN, click the button of your U2F key to confirm the key.
Note
If the hostname of your system changes, e.g. because of DHCP in different networks, you would be unable to login. In order to prevent that, it is recommended to specify the above mentioned options and replace
hostname
with the actual hostname.
If you own more than one key, append the next ones with
$ pamu2fcfg -i pam://
hostname
-n >> ~/.config/Yubico/u2f_keys
Note
The
-n
in the above command is required. It will omit the username portion of the generated entry as required in the spec for subsequent entries for the same user. Multiple entries with the same username will cause unpredictable behaviour in PAM. Also, do not add line breaks manually. The file
u2f_keys
must have only one line.
[1]
Passwordless sudo
Warning
Before making any changes to your configuration, start a separate shell with root permissions (e.g.
sudo -s
). This way you can revert any changes if something goes wrong.
Add
/etc/pam.d/sudo
auth            sufficient      pam_u2f.so cue origin=pam://
hostname
appid=pam://
hostname
as the first line. Be sure to replace the
hostname
as mentioned above. Then create a new terminal and type
sudo ls
. Your key's LED should flash and after clicking it the command is executed. The option
cue
is set to provide indication of what to do, i.e.
Please touch the device
.
In order to make the token the only method of sudo (ie. no password fallback) you will need to comment out the other auth methods present. This is usually just the default system-auth include.
/etc/pam.d/sudo
#auth           include         system-auth
You should also change
sufficient
to
required
in the above
pam_u2f.so
line.
Warning
This will mean that no user on the system will be able to sudo without a U2F token configured.
GDM login
Add:
/etc/pam.d/gdm-password
auth            required      pam_u2f.so nouserok origin=pam://
hostname
appid=pam://
hostname
after the existing
auth
lines. Please note the use of the
nouserok
option which allows the rule to fail if the user did not configure a key. This way setups with multiple users where only some of them use a U2F key are supported.
Note
This method will not work with encrypted home partitions because the decryption is not done before the login process completed, so the
u2f_keys
file is unavailable. In this case use a central mapping file as explained in the
official documentation of pam-u2f
.
Some multi-function security keys (ex. Trezor Model T) which can do U2F / PAM may not advertise the feature on system boot which is intentionally out of the CTAP 2.0 specification
[2]
. With multiple U2F keys present, this can result in two-minute long delays when used with GDM as pam-u2f does sequential lookups and will wait for the (Trezor) device to timeout before offering presence / touch with the secondary U2F key
[3]
. You could try adding the
nodetect
option alongside
debug
and finish any device specific login (ex. screen PIN) before GDM loads.
SDDM/KDE
SDDM
does not appear to support pam_u2f with initial user login.
Autologin
can be used instead, and then edit
/etc/pam.d/kde
to just control screen locking.
If you are using a U2F key with biometric authentication (e.g. Yubikey Bio) and want 1FA, use
/etc/pam.d/kde-fingerprint
, commenting out the pam_fprintd.so line and placing your changes in its place. This avoids an unnecessary "unlock" button that gets displayed after authentication, rather than simply unlocking immediately
[4]
.
For example:
/etc/pam.d/kde-fingerprint
#%PAM-1.0

auth       required                    pam_shells.so
auth       requisite                   pam_nologin.so
auth       requisite                   pam_faillock.so      preauth

# take over fprintd for u2f since yubikey bio is a fingerprint reader and bypasses kscreenlocker's "unlock" button
#-auth      required                    pam_fprintd.so
auth required pam_u2f.so cue pinverification=0 userverification=1

auth       optional                    pam_permit.so
auth       required                    pam_env.so

account    include                     system-local-login

password   required                    pam_deny.so

session    include                     system-local-login
Warning
Do not use
auth sufficient
in
/etc/pam.d/kde-fingerprint
as you might in other PAM config files. This will cause failed authentication attempts to bypass the lock screen.
Other authentication methods
Enable the PAM module for other services like explained above. For example, to secure the screensaver of
Cinnamon
, edit
/etc/pam.d/cinnamon-screensaver
.
For
Polkit
, copy the default configuration at
/usr/lib/pam.d/polkit-1
to
/etc/pam.d/polkit-1
and make your changes there.
Troubleshooting
If you managed to lock yourself out of the system, boot into recovery mode or from a USB pen drive. Then revert the changes in the PAM configuration and reboot.
In case the pam-u2f module silently fails, add
debug
keyword to the auth line in a file in
/etc/pam.d/
.
OpenSSH
OpenSSH
≥8.2 supports FIDO/U2F hardware tokens natively, see
SSH keys#FIDO/U2F
.
Data-at-rest encryption with LUKS
This article or section is a candidate for moving to
systemd-cryptenroll
.
Notes:
systemd-cryptenroll
supports more than just FIDO. (Discuss in
Talk:Trusted Platform Module#move systemd-cryptenroll to separate article
)
Since version 248,
systemd
can be use to unlock a
LUKS partition
using a FIDO2 key.
First, you will need to setup your
/etc/crypttab
file (see below), or customize your
initramfs
if you wish to unlock your root partition. The full procedure is similar to the use of a TPM chip for unlocking. See
systemd-cryptenroll#Trusted Platform Module
.
To register the key, you will need to use the
systemd-cryptenroll
utility. First, run the following command to list your detected keys:
$ systemd-cryptenroll --fido2-device=list
Then you can register the key in a LUKS slot, specifying
auto
value (or path to the FIDO2 device such as
/dev/hidrawX
if you have multiple):
$ systemd-cryptenroll --fido2-device=auto /dev/sd
X
Non-root partitions
For a non-root data partition the
crypttab
would look like this:
/etc/crypttab
data /dev/sd
X
none fido2-device=auto
This should also work if your encrypted partition is a logical volume managed under
LVM
:
/etc/crypttab
data /dev/vg1/data none fido2-device=auto