Using U2F for Two-factor Authentication

[Edited Steps 4&5 to clarify symlinking files to deal with authconfig]
[Added Trezor link to Docs section]

There is some useful information on the web, but it often seems a bit dated and sometimes related to the “big Yubikey” (in challenge/response mode) rather than U2F. These are my notes on set-up, please consider them work-in-progress and report back with your findings, so I can update the procedure.

I’m using Fedora, so things may be different in your distro. I’m also using Yubikeys with a touch button. Keys without a button operate differently, you probably have to remove/re-insert instead of touching the key.

Consider what you will do in case of loss or failure of your second factor. You need to prepare so you don’t get locked out.
Setting up PAM (Pluggable Authentication Modules) means wrestling with the beast that guards your computer. You could lock yourself out, or inadvertently reduce your security. I’m no expert in PAM, so while I think my set-up works I really can’t guarantee much. Even the pros shoot themselves in the foot occasionally.

To avoid locking myself out during the set-up, I have done things step by step. As an extra security measure you could create a new user for experimenting with, and only add U2F to your own account once you are certain the set-up works as intended.

Things you need
At least one U2F key, obviously. I use two of them, one as a backup.

Install the PAM module pam_u2f and the pamu2fcfg config utility. These should be in the repos. The packages are called pam-u2f and pamu2fcfg in Fedora, but perhaps the names are a bit different in your distro.

Docs
The man pages for pam_u2f and pamu2fcfg
Yubico: Using your U2F Yubikey with Linux
Gentoo: https://wiki.gentoo.org/wiki/Pam_u2f
Debian: https://blog.liw.fi/posts/u2f-pam/
Trezor: https://blog.trezor.io/trezor-u2f-login-into-your-linux-mint-bd3684d4a8ba?gi=b26bdea72ced

Step 1: Enrolling Your U2F Keys

This tells PAM which U2F keys are allowed.

You can store the file with enrolled keys in your home directory or in a system-wide directory. I have had trouble with the first option (permissions, missing environment variables), so I suggest using a system-wide directory. That is also your only option, in case your home directory is encrypted [Note 1]. Other than that, the procedure is pretty straight-forward.

Docs have different opinions on the exact location. I chose to gather all two-factor configuration in one place - be it for U2F, authenticator app, scratch codes or Yubikey challenge-response.

First, just check that the basic things work. Insert your key, then in a terminal
$ pamu2fcfg --origin='pam://localhost'
…and touch your U2F key when it flashes. (You will be prompted to insert the key by pamu2fcfg, if you forget to.)

The command should print a lot of character data. (The specific format is described below and in the man page for pam_u2f.) If not, or if there is an error, try the command again, but this time add --debug to get verbose output about the process.

If all seems good, now do this [Notes 2…4]
$ sudo mkdir -p /etc/2fa/u2f/
$ sudo pamu2fcfg --origin='pam://localhost' > /etc/2fa/u2f/u2f_keys
…and touch your U2F key when it flashes. This puts the registration data into a file.

For your second (,and third, …) device, invoke the config utility like so:
$ sudo pamu2fcfg --origin='pam://localhost' --nouser >> /etc/2fa/u2f/u2f_keys

Open the file and verify that there is a single line in the following format
username:longstring1a,longstring1b
or the following format if you registered more than one key
username:longstring1a,longstring1b:longstring2a,longstring2b[:...]
In other words, each line in the file has to start with the user name, followed by the data for all of this user’s enrolled keys, all separated by colons.

Finally, to keep prying eyes out, do
$ sudo chmod -R o-rwx /etc/2fa
I don’t think this matters very much for U2F, but will be essential if at some stage you add an authenticator app.

That’s it! Now you’re ready to set up PAM to use your U2F key(s).

Notes

  1. If your home directory is encrypted, you need to put the file elsewhere, because decryption happens after login. If you just use full-disk encryption (like I do) then you’re good.
  2. You can change --origin='pam://localhost' to a string of your liking
  3. You can also omit --origin='pam://localhost', in which case it will default to your actual hostname.
  4. The --origin will be encoded into the authorization file and has to match the origin used by PAM when you log in. So you will be locked out, if you use the default and your hostname changes for whatever reason! For example, depending on what network you connect to. So it seems safer to explicitly set --origin here and also explicitly set it in the PAM configuration.

Step 2: Initial PAM Configuration

The goal here is to find out if your PAM/U2F setup works. The key is still not required, so you should be able to log in even if there is a problem. You will be trying out two-factor login to a pseudo terminal, leaving desktop logins untouched.

Edit the /etc/pam.d/login file and add pam_u2f.so to the auth section. [Notes 1…4]

Modules will be invoked from top to bottom, so you can choose if you want password or U2F to come first. I wanted to start with the password, so added U2F as the second line in my file [Note 5, 6]:
auth substack system-auth
auth optional pam_u2f.so origin=pam://localhost authfile=/etc/2fa/u2f/u2f_keys cue nouserok
auth include postlogin
account required pam_nologin.so
account include system-auth
...

Now

  • insert your U2F key
  • open a pseudo terminal
  • login with your user name and password
    You should then be prompted to touch the key, and once you do, you should be logged in. Do note that pam_u2f will fail if the U2F key is not present, but because the module is optional it will fail silently and let you in without your second factor.

Repeat the procedure for all enrolled U2F keys before proceeding.

Notes

  1. PAM configuration is split into numerous files that reference each other. This is done so that different types of logins (via GUI, from pseudo terminals…) can share basic settings.
  2. Actual file names seem to vary by distro
  3. The whole PAM configuration structure is created by authconfig, and is symlinked in a way that lets you override the generated files without having your changes reverted on the next authconfig run. Whenever that happens.
  4. On Fedora, you also need to deal with SELinux
  5. The original file contents may be different on your distro
  6. The interactive option is recommended if your device doesn’t have tactile trigger. It makes PAM prompt and wait before testing the presence of a U2F device.

Step 3: Making U2F a Requirement

Now it’s time to make the U2F key a requirement, actually securing your logins with a second factor. We’ll make it a “soft” requirement - i.e. a requirement only for users that have U2F keys enrolled [Note 1…3]. Any other user will be able to log in with just their password.

Simply change the U2F line in /etc/pam.d/login to
auth required pam_u2f.so origin=pam://localhost authfile=/etc/2fa/u2f/u2f_keys cue nouserok
Then try logging in to a pseudo terminal. This should fail if you have not inserted your U2F key, or succeed if the key is present and you touch it.

When this works, you can move on to cover more things with U2F.

Notes

  1. The nouserok option makes authentication succeed if the user has no U2F devices enrolled or if authfile is missing/malformed. This lets you enable U2F for selected accounts.
  2. The nouserok option also lets anyone with write access to the u2f_keys file disable U2F.
  3. Omit the nouserok option to make U2F mandatory for all accounts. Make sure you have keys enrolled before doing this, as accounts without keys will be locked out.

Step 4: Adding U2F to Other Commands

You probably also want to protect su, sudo and other commands with a second factor. After all, if a command needs authentication, then it should do it to the full extent. You can achieve this in two ways: either you make changes to the PAM set-up for each command, or you put the changes in a central file that gets included or substacked from the different configurations. This is where you need to consider the structure your distro uses in the /etc/pam.d/ directory, as it may be different from mine.

On Fedora 28, I have a dozen files for different commands (or groups of commands) that rely on system-auth for most of their work. This file would be the central place to insert pam_u2f. [Note 1] On Fedora, changing system-auth also got me 2FA for things like adding a new user in Gnome Settings. [Note 3] To take this route, follow Red Hat’s instructions (skip to section Keeping Custom Settings with authconfig):
cp system-auth-ac system-auth-2fa
ln --symbolic --force /etc/pam.d/system-auth-2fa /etc/pam.d/system-auth
…and then edit system-auth-2fa to insert pam_u2f. Also remember to remove pam_u2f from the login file!

If, instead, you choose to change the individual files, there is an important thing to watch out for, and that is the method used to invoke system-auth. My original sudo file used include, which made PAM ignore the U2F module on the next line. Changing include to substack (like it already was in the login file) solved the problem. [Note 2]

My improved /etc/pam.d/sudo file with U2F looked like this after editing:
auth substack system-auth
auth required pam_u2f.so origin=pam://localhost authfile=/etc/2fa/u2f/u2f_keys cue nouserok
...

After saving, check su, sudo, chsh, etc. On Fedora, changing system-auth also got me 2FA for things like adding a new user in Gnome Settings. [Note 3]

Notes

  1. There is an arrangement of files and symlinks to allow changing the configuration without having it overwritten by authconfig later on. The specific PAM files include or substack system-auth, which is a symlink to the generated system-auth-ac file. By changing the system-auth symlink to a different file, the new set-up will not be overwritten. It will not get any updates either, of course.
  2. This is because include means literally stuffing the lines from the included file in place of the include, whereas substack considers the other file as a separate entity. Any successful sufficient module in an included file will discard all subsequent modules, even in the “top” file, whereas a successful sufficient module in a substacked file will only “return” from that file.
  3. Or any other action depending on polkit-1

Step 5: Using U2F for Desktop Login

This is another case where you need to consider the structure your distro uses in the /etc/pam.d/ directory, as it may be different from mine.

Fedora 28 with Gnome has files called gdm-something. I have six of those. Instead of a single common configuration that gets included, there are three for three different authentication methods: password, fingerprint, and smartcard [Note 1]. The one to change would be password-auth. However, among the things that use the password-auth file are atd, crond, cups, and sshd. Because I’m not sure these will respond well to 2FA [Note 2], I have decided to change the gdm-password file instead. If you decide to go for password-auth, do the same copy/symlink dance as for system-auth in Step 4 above.

The task, then, is just to add the same line to the chosen configuration file(s). To prevent being left out in the rain while working on this change, I logged into a pseudo console, made myself root, and edited the configuration file from there. Then I switched to the desktop, locked the screen/logged out, and logged back in to check that things worked.

Notes

  1. The set-up seems to allow logging in with just a fingerprint (or, a smartcard). Whether that is a good idea can be debated.
  2. For instance, I think sshd would try to access a U2F key on the server side, not a key on the user’s machine.
  3. TODO: What about remote?

Final notes

If you have come this far: Congratulations!

You should also protect root, once the set-up works. You can use the same U2F device(s) as for your own account. Enrolling them again will create new cryptographic key pairs each time; using the same device for multiple accounts and services is the key feature of U2F.

It should be possible to use U2F plus an authenticator app or scratch codes, to save yourself from buying a backup U2F key. In such a set-up, you would even be able to recover if USB stops working on your computer. In addition, you also get the problems with authenticator apps (e.g. someone could steal the shared secret without you noticing), and setting up PAM becomes more complicated. I would suggest putting all of the two-factor stuff into a separate file, and then substack that file as needed.

When you’re done, clean up PAM debug if you used it.

And remember to share your findings below!

4 Likes

I found this too:

1 Like

Brilliant! If you follow those instructions, do read the man pages and check out some of my notes, so you understand what default values you get.

Added the link to OP.

1 Like

I set up second factor auth via pam for system login and all sudo commands, pseudo-2FA for LUKS decryption of my drives (split-passwords via a difficult to remember and type static password, and PGP-encrypted files on those LUKS drives for things requiring additional security. I did all of this with a yubikey!

The only thing I am missing now is tamper-evident boot, which I will be able to set up once my Librem Key arrives.

It wasn’t clear when I first starting reading this post so just in case others stumble upon the same thing: this post is not about using U2F on the librem key itself. It’s how to configure a server or at least another machine to be authenticated with another U2F token, for example with a Yubikey.

As far as I know, the Librem Key still doesn’t support U2F, as discussed here:

Thanks for the tutorial by the way, it looks well made! :tada:

@dc3p , good to hear you managed to set up all of that. If you have any experiences or challenges to share when setting up U2F, please let me know so I can update the tutorial.

1 Like

No, this post is not about logging in to a server, it is about logging in to your own computer (laptop/phone/…) using U2F.

Setting up U2F for logging in to other peoples’ computers (web or other servers) is much easier:

  • Enable U2F on your account
  • Enroll your key(s) and/or create backup codes

…provided the admins have already enabled U2F on the server, of course…

@dc3p, sorry, it seems I can no longer edit my op :frowning: so improvements have to go somewhere else. I’ll see if there is a wiki.

Update: Can’t find a wiki here that I’m allowed to edit. And since I haven’t tried on PureOS, maybe it should go somewhere else anyway.

I’ll tell you, your guide way helpful and got me going in the right direction, but I also had to do other research and improvise a bit. Since I am using PureOS, I may create a guide based on yours, but tailored for the PureOS crowd :D.

1 Like

Well, server, computer - it’s all computers after all. :slight_smile: The point I was mostly trying to make is that this is not about U2F support in the Librem Key.

Posts should be editable by their authors. I just posted Single sign on with shop? and I can edit the post by clicking on the little “pencil” logo at the bottom of the post. Don’t you have that button? Maybe you can’t edit after a while?

The PureOS version is live: System U2F Authentication with YubiKey.