Using U2F at Linux Login
May 08, 2018
5 minute read

Introduction

FIDO is the next big thing in multi factor authentication. Here is how I started using it to login my personal Linux computer.

VERY IMPORTANT: You are going to change a very critical system file (/etc/pam.d/common-auth) in this tutorial. If anything goes wrong, you may not be able to login to your computer anymore. Test what you are doing first in another system. No liability is assumed.

23.07.2018: I have updated the steps in this tutorial for a clean Ubuntu 18.04 installation on a linux container and to use libpam version 1.0.7.

Requirements

  • a Linux computer. I am using Ubuntu 18.04 LTS. In your distro, there might be differences on the locations of files. For this tutorial, I have installed a clean Ubuntu 18.04 on a linux container.
  • a FIDO U2F device. I am using a Yubico Security Key.

Setup PAM

Linux uses PAM (Pluggable Authentication Modules) to handle all authentication tasks. Since I am going to modify how I login (authenticate) to the system, using FIDO U2F, I need a PAM module providing this functionality.

$ apt-cache policy libpam-u2f
libpam-u2f:
  Installed: (none)
  Candidate: 1.0.4-2
  Version table:
     1.0.4-2 500
        500 http://de.archive.ubuntu.com/ubuntu bionic/universe amd64 Packages

libpam-u2f package is what I need. However, version 1.0.4 is released in 2016, and I really need some of the patches done after that, so I will use the latest version, which is 1.0.7 at the moment (23.07.2018), and build it from the source.

$ git clone https://github.com/Yubico/pam-u2f
$ cd pam-u2f
$ git tag
pam_u2f-0.0.0
pam_u2f-0.0.1
pam_u2f-1.0.0
pam_u2f-1.0.1
pam_u2f-1.0.2
pam_u2f-1.0.3
pam_u2f-1.0.4
pam_u2f-1.0.5
pam_u2f-1.0.6
pam_u2f-1.0.7
$ git checkout pam_u2f-1.0.7

The build instructions are given in the project’s github page. Following them (and before that I do an update & upgrade):

$ sudo apt-get update
$ sudo apt-get upgrade
$ sudo apt-get install autoconf automake libtool libpam-dev asciidoc xsltproc libxml2-utils docbook-xml --no-install-recommends
$ autoreconf --install
$ apt-get install autoconf automake libtool pkg-config libu2f-host-dev libu2f-server-dev --no-install-recommends

The instructions says we can configure and make now but this gives an error and I think we need to run autoreconf again, so:

$ autoreconf --install
$ ./configure
$ make

This should end without any error. Then we can install it:

$ sudo make install

The library is (by default) installed here:

$ file /lib/x86_64-linux-gnu/security/pam_u2f.so
/lib/x86_64-linux-gnu/security/pam_u2f.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, BuildID[sha1]=794a9f39069902d65f48f1f369496731570bdaa5, with debug_info, not stripped

Create a Backup User

Before using the PAM library, I create a new user in sudo group, with a very long/complex password and keep this in a secure place. I will not use this user normally, but keep it as a backup in case U2F authentication fails or the U2F device is broken or lost.

$ sudo adduser <backup_user>
$ sudo usermod -aG sudo <backup_user>

Register a U2F Token

I will use the pamu2fcfg tool that is built together with pam_u2f.so above. The syntax is like below, all arguments are optional:

$ pamu2fcfg -uusername -opam://myorigin -ipam://myappid

I run this with the same user, so I omit -u, and I explicitly specify the origin and appid rather than using the default ones, so:

$ pamu2fcfg -opam://mydesktop -ipam://mydesktop

This will output a configuration line which I need and after running this the U2F device will blink and I touch it to complete the registration. I actually redirect it directly to the config file:

$ cd ~
$ mkdir .config/Yubico
$ pamu2fcfg -opam://mydesktop -ipam://mydesktop > .config/Yubico/u2f_keys

This path is the default path pam_u2f.so will look for each user.

Configure PAM

I add the following line to the end of /etc/pam.d/common-auth:

auth sufficient pam_u2f.so debug cue nouserok origin=pam://mydesktop appid=pam://mydesktop

Since I set the origin and appid when using pamu2fcfg, I also use origin and appid parameters here.

This configuration will make use of U2F device, if $HOME/.config/Yubico/u2f_keys file is present, and if it is not present (or invalid) authentication will succeed (nouserok parameter). If you use the 1.0.4 version, this is not going to work, so make sure you use the latest version of pam_u2f. Parameter cue prompts a message to remind to touch U2F device.

Very Important: The u2f_keys file should not be under an encrypted file system, because files can be decrypted only after a successful authentication which requires u2f_keys file.

It is also possible to use a single system wide configuration (single u2f_keys file) rather than using per-user u2f_keys file using the authfile parameter of pam_u2f.

Test

I configured my user with u2f_keys file, and the admin user without. At this point, I try if authenticating as the U2F configured user asks for the U2F device, and I can successfully authenticate using U2F, and also authenticating with the admin user does not ask for it. For example (and my u2f user is mete, admin user is paula):

Note: when you have debug in pam_u2f.so configuration line in common-auth, you will see some debug output as well. Below, I omit that output.

$ sudo ls
[sudo] password for mete: <type password>
Please touch the device.
<the U2F device should be blinking now>
<touch the U2F device>

... you will see file listing ...

If I try the same with the admin user:

$ su - paula
[sudo] password for mete: <type password>

... you will see file listing ...

So it seems like the setup is working.

I actually tried not only sudo, but normal login and lock screen as well.

Go Live

As everything is working as expected, I modify the U2F config in common-auth and change sufficient to required and remove the debug parameter.

auth required pam_u2f.so cue nouserok origin=pam://mydesktop appid=pam://mydesktop

Since it is “required” now, pam_u2f will succeed when:

  • there is no U2F registration (no u2f_keys file) for the user trying to authenticate (nouserok parameter).
  • there is a U2F registration given under $HOME/.config/Yubico/u2f_keys of the user trying to authenticate and U2F device is plugged, touched and U2F authentication process completes successfully.


The best way to receive blog updates is to follow me on Twitter: @metebalci