YubiKey, for multi-factor authentication on Linux.

YubiKey Authentication With pam_u2f.so

YubiKey and U2F

YubiKey cryptographic device
Amazon B0BVNPWPCN

A YubiKey is a small hardware authentication device that plugs into a USB port. Several models are available, for US$ 20–70.

The FIDO protocol verifies that the user has access to the private key corresponding to the public key registered with the system. YubiKey devices can run FIDO using an elliptic curve key pair installed at the factory.

The PAM mechanism on Linux supports the pam_u2f.so library module. You can specify authentication using U2F or Universal 2nd Factor devices communicating with FIDO. YubiKey and smart card devices can be the added second factor.

The libpam-u2f package contains the PAM library module and the needed commands on Debian, Ubuntu, and derivatives.

Let's see how to set up YubiKey authentication with the pam_u2f.so PAM library.

YubiKey authentication device.

U2F — Getting Started

The YubiKey contains a secp256r1 elliptic curve key pair (a.k.a. prime256v1 or NIST P-256). The public key is in the form of a certificate signed by Yubico. Verifying that certificate proves that the device was made by Yubico, giving the verifier confidence that the algorithms are implemented properly, certified by the FIDO Alliance.

To use semi-formal terminology, the user with the YubiKey is the principal, the entity that wants to authenticate or prove their claimed identity.

The various PAM-aware services running on the Linux operating system are the authenticators, entities that verify the principal's claimed identity. We might consider a Linux server to be a generalized authenticator, hosting several services — text console with login, graphical console with gdm, remote connections with sshd, and so on. Each of those would have its own PAM file in /etc/pam.d/ telling it how to authenticate users.

The Linux server registers the user's device, recording the fact that they own a specific YubiKey device. Starting an authentication event, the user connects their device electrically through a USB port or by radio through NFC or Near-Field Communication.

Now, in an overly simplified design...

When it's time to authenticate a user, the Linux server generates a random challenge and sends it to the device. The device generates a digital signature for the challenge, using its embedded private key, and sends the signature and its certificate back. The Linux system could first verify the certificate, showing it's really the public key of that device and thus belongs to that user. Then it could verify the digital signature over the randomly generated challenge, showing that the device contains the correct private key.

The problem is that if you use the device for multiple accounts, a breach of one could become a breach of all of them. Several YubiKey models are available, and all are small. But at US$ 20–70, users won't want to have to own one for each account.

Improving the Design

During the registration, the Linux server sends an origin specifying the server to which the user will authenticate, an application ID specifying which application on that server, and a random seed. The origin might be pam://servername, and the appplication ID might be pam://login or pam://sshd, or perhaps just pam://servername again for the application ID. In that last case, that one registered identity would work for all applications on that origin, or server.

The YubiKey device then generates a new unique key pair for that origin and application. That new key pair is called the Registering Dependent Keys. This new key pair is used for this origin–application identity, so the one device supports its owner's many specific identities across multiple services running on multiple systems.

The server keeps a record for that user. That record includes their user name, the key handle specifying which key pair, and the public key of that pair.

At authentication time, the device is told which key to use to generate the signature.

Registering a User

pamu2fcfg
manual

You use the pamu2fcfg command to register a user. By default the origin will be pam://$HOSTNAME and the application ID will be the same. The user name will be the same as the person running the registration program. Command-line parameters allow you to specify details. The command outputs one very long line with no newline at the end, formatted as:
Username:KeyHandle:PublicKey. Let's do this for a user named cromwell on a system named laptop:

# pamu2fcfg --origin=pam://laptop --username=cromwell ; echo
cromwell:mUXDuyrXnRitucPGhB__UFH7hOCSKInTLMNLIPOvy1ZNhjqAx0cxA7NELmoYYmpvPwLs9KsHBAzmBWWM-GdloA,0422aadcae1c953a27e9451f55274188bb4665e84f56d5c900bbc08cd1a790a6bdaaa08a0a6dc7929a34ab87eb13a307d0d9f0f9798f680d3307fae4581b2b0ea3
\---+--/ \-------------------------------------------+----------------------------------------/ \---------------------------------------------------------------+----------------------------------------------------------------/
username                                        key handle                                                                                                  public key

The output is different each time you run the command. This is because each time the YubiKey device generates a new key pair based on the origin, application ID, and the random seed.

# pamu2fcfg --origin=pam://laptop --username=cromwell ; echo
cromwell:9tAYwte2AqtdwvfqY2p9yqxlY1WBWM71uxA19nyM8-brl5KnSaDWbBET7m_MUDosKk5CcTLQ4UNaGBwoEjk4pQ,04aab5969e74c5b66bccfb3bc3c5767b57cf4a776ca6ca7c8d8e3bc9f4bf0326beec77ec70934c5388674a20e69c4dc71269ec0a57ac2f6f28419cc87f1a0be875
# pamu2fcfg --origin=pam://laptop --username=cromwell ; echo
cromwell:Wjybc8zDNmrbYCpVX1ZR_B2RvpYFSI_NfxURqTit5jSmpgxthwZWDEtyf9GsRba6SrNgNu4MqbnJi5VFxtJs4w,04f76bf1dca36068a7d7547e7c61d98e3fb9cfb23d53e7d549bbc3123a204c28afaaa41bf115f6185c748538fee01b6de7237cc774203b90cfa9fe43254c5a64b3
# pamu2fcfg --origin=pam://laptop --username=cromwell ; echo
cromwell:EWnXSzNq6CbnemflNB-4oSAB0F8a8m4ajT1ZsiTOXhIS-pIJ0mOEwFMIaMbfo8RKCjbMwnuBhmAtj_orTlqEBg,0472d694c6fb214cfb0b4b0196cd029ff98f4e1fb51d66a841c52592a89b353e32df3524bb28ed7c2634b10bf98db1a5148d1f0da6ce1b37b73b673713ba5568fd
# pamu2fcfg --origin=pam://laptop --username=cromwell ; echo
cromwell:vmzOGnYnomcjuHYKVIu_kv9OeLS9p71ub1OPrROUx1wdDu0RKL7yHjtjFhEvqICy39R_4Rw1-wMn9vS4AQrQBA,048b6185c13745d3ceac42a34791b1a961651e68a77b04c3b28c61933b40a889189dc9322c36057bd4ae7758ad568221ad512cae91a5397b2b7a061a76debad857
# pamu2fcfg --origin=pam://laptop --username=cromwell ; echo
cromwell:CoZ-GrXSfZvwusIzQVKpzgfu7SrFokeHfwaCUY4Dfu4PaESuhZbGHTfvWnsLxVpWWowYxztmOo57McYlNuNC9A,0488b18a1f9b9eaad0dc058427600d9751786161baeb1477f8f7fd5062bb19cae040624adbce38e52a167f26d77bd9b3c4711d2b4507d59d361b8197d607ff274f
# pamu2fcfg --origin=pam://laptop --username=cromwell ; echo
cromwell:tYBy1lHWm35JS2vUdfxaL_8NNZjjPyzxTrGnIBUQQbUOBjkbYrflnuUKblh5yy35zDVmKt6tY3fxSqMajxpS-w,041ca0d0a6b7238bf2dbf5d56d58bb091d2b78aab7bdb420b16eb4b189cdf9914c32acde50386e94f784c644cf721237fb9528e9d91f36824439e2d29b4907b68e
# pamu2fcfg --origin=pam://laptop --username=cromwell ; echo
cromwell:Naxyr8MTqYcC_J0XrbnsAdxqdSBMCfUk25ePx7E491QXbXuyH5K4YjFa2ut6kV4GkG7e698Vi0gEvdwYmY5zgg,04a5f6df17855f0c206fe2cdeeb6d88533e6bb7b7e8452e4ff68d03d8fe679ec90a2ec12eaa78987550ea9e27ae086006d72c561d156e807b1caca85bbc7705450
# pamu2fcfg --origin=pam://laptop --username=cromwell ; echo
cromwell:glTYFaOvNdzvu5sAi2vDz_kflMk9aKAtdUlIavsY50FaKoCChy331UV-TI6qbobEodcRNaCtS7ynl_HPZq4Bxw,0469a1bc0e85fc5f4888d5024d76e294bb2098916a586ad473bab927c00e239dee1e73eccd46d86e389e4a718a3e1baf6df49ad4a4b8b1e84f691e02843ef76d4d

Storing the Registration

The default is that each user has a one-line file $HOME/.config/Yubico/u2f_keys.

Alternatively, you could create one file somewhere under /etc with one line per user. Then you would need to tell the PAM module where to find this system-wide record of users' uniquely generated public keys.

Configuring PAM

The file /etc/pam.d/common-auth is included by several service files on Debian and Ubuntu. It contains the following when you first install the system.

#
# /etc/pam.d/common-auth - authentication settings common to all services
#
# This file is included from other service-specific PAM config files,
# and should contain a list of the authentication modules that define
# the central authentication scheme for use on the system
# (e.g., /etc/shadow, LDAP, Kerberos, etc.).  The default is to use the
# traditional Unix authentication mechanisms.
#
# As of pam 1.0.1-6, this file is managed by pam-auth-update by default.
# To take advantage of this, it is recommended that you configure any
# local modules either before or after the default block, and use
# pam-auth-update to manage selection of other modules.  See
# pam-auth-update(8) for details.

# here are the per-package modules (the "Primary" block)
auth	[success=1 default=ignore]	pam_unix.so nullok_secure
# here's the fallback if no module succeeds
auth	requisite			pam_deny.so
# prime the stack with a positive return value if there isn't one already;
# this avoids us returning an error just because nothing sets a success code
# since the modules above will each just jump around
auth	required			pam_permit.so
# and here are more per-package modules (the "Additional" block)
# end of pam-auth-update config

You can greatly simplify the file and require both YubiKey and password authentication:

#
# /etc/pam.d/common-auth - authentication settings common to all services
#
# This file is included from other service-specific PAM config files,
# and should contain a list of the authentication modules that define
# the central authentication scheme for use on the system
# (e.g., /etc/shadow, LDAP, Kerberos, etc.).  The default is to use the
# traditional Unix authentication mechanisms.
#
# WARNING: Do NOT use pam-auth-update as it will change this file
# and destroy your settings.

# Ask for the password and then for the token, failing at the end
# if either is wrong.
auth	required	pam_unix.so
auth	required	pam_u2f.so cue

Or, if you want to allow either YubiKey or password authentication:

#
# /etc/pam.d/common-auth - authentication settings common to all services
#
# This file is included from other service-specific PAM config files,
# and should contain a list of the authentication modules that define
# the central authentication scheme for use on the system
# (e.g., /etc/shadow, LDAP, Kerberos, etc.).  The default is to use the
# traditional Unix authentication mechanisms.
#
# WARNING: Do NOT use pam-auth-update as it will change this file
# and destroy your settings.

# It either UNIX password or YubiKey succeeds, this immediately exits
# with success.  If neither succeeds, this fails.
auth	sufficient	pam_unix.so
auth	sufficient	pam_u2f.so cue
auth	required	pam_deny.so

See the pam_u2f(8) manual page for more on PAM module options and parameters. You can add the debug parameter to get helpful troubleshooting information.

Going Deeper: Verbose U2F Authentication

We'll start a script session to capture this output. Let's require the password first and then the token, with the token in debug mode with lots of narrative output. Then we'll run the login program and authenticate with a configured user account.

# script u2f-debug-output
Script started, file is u2f-debug-output
# cat /etc/pam.d/common-auth
auth	required	pam_unix.so
auth	required	pam_u2f.so cue debug
# cat ~cromwell/.config/Yubico/u2f_keys
cromwell:vsmDodhUsAc7j8HfnNYcWokggFRltEb6DgwvB_02Seja55XL5k0BV9eRp9ydJZqgVIbO8hjHnm1pCJDdT7xlFQ,041205c9eb8d0d297ee8cc82d7a592645a5d55288c5d203191ebbcee46422aca69e3cf2ee591361fceb28c5dbe59bcfa7fe5e593bbbfb8e10cd11f1f45160311c4
# login
laptop login: cromwell
Password: ØØØØØØØØØØØØØØØ
debug(pam_u2f): ../pam-u2f.c:99 (parse_cfg): called.
debug(pam_u2f): ../pam-u2f.c:100 (parse_cfg): flags 0 argc 2
debug(pam_u2f): ../pam-u2f.c:102 (parse_cfg): argv[0]=cue
debug(pam_u2f): ../pam-u2f.c:102 (parse_cfg): argv[1]=debug
debug(pam_u2f): ../pam-u2f.c:104 (parse_cfg): max_devices=0
debug(pam_u2f): ../pam-u2f.c:105 (parse_cfg): debug=1
debug(pam_u2f): ../pam-u2f.c:106 (parse_cfg): interactive=0
debug(pam_u2f): ../pam-u2f.c:107 (parse_cfg): cue=1
debug(pam_u2f): ../pam-u2f.c:108 (parse_cfg): nodetect=0
debug(pam_u2f): ../pam-u2f.c:109 (parse_cfg): manual=0
debug(pam_u2f): ../pam-u2f.c:110 (parse_cfg): nouserok=0
debug(pam_u2f): ../pam-u2f.c:111 (parse_cfg): openasuser=0
debug(pam_u2f): ../pam-u2f.c:112 (parse_cfg): alwaysok=0
debug(pam_u2f): ../pam-u2f.c:113 (parse_cfg): authfile=(null)
debug(pam_u2f): ../pam-u2f.c:114 (parse_cfg): authpending_file=(null)
debug(pam_u2f): ../pam-u2f.c:115 (parse_cfg): origin=(null)
debug(pam_u2f): ../pam-u2f.c:116 (parse_cfg): appid=(null)
debug(pam_u2f): ../pam-u2f.c:117 (parse_cfg): prompt=(null)
debug(pam_u2f): ../pam-u2f.c:169 (pam_sm_authenticate): Origin not specified, using "pam://laptop"
debug(pam_u2f): ../pam-u2f.c:181 (pam_sm_authenticate): Appid not specified, using the same value of origin (pam://laptop)
debug(pam_u2f): ../pam-u2f.c:192 (pam_sm_authenticate): Maximum devices number not set. Using default (24)
debug(pam_u2f): ../pam-u2f.c:210 (pam_sm_authenticate): Requesting authentication for user cromwell
debug(pam_u2f): ../pam-u2f.c:221 (pam_sm_authenticate): Found user cromwell
debug(pam_u2f): ../pam-u2f.c:222 (pam_sm_authenticate): Home directory for cromwell is /home/cromwell
debug(pam_u2f): ../pam-u2f.c:229 (pam_sm_authenticate): Variable XDG_CONFIG_HOME is not set. Using default value ($HOME/.config/)
debug(pam_u2f): ../pam-u2f.c:265 (pam_sm_authenticate): Using authentication file /home/cromwell/.config/Yubico/u2f_keys
debug(pam_u2f): ../pam-u2f.c:278 (pam_sm_authenticate): Dropping privileges
debug(pam_u2f): ../pam-u2f.c:284 (pam_sm_authenticate): Switched to uid 1001
debug(pam_u2f): ../util.c:105 (get_devices_from_authfile): Authorization line: cromwell:vsmDodhUsAc7j8HfnNYcWokggFRltEb6DgwvB_02Seja55XL5k0BV9eRp9ydJZqgVIbO8hjHnm1pCJDdT7xlFQ,041205c9eb8d0d297ee8cc82d7a592645a5d55288c5d203191ebbcee46422aca69e3cf2ee591361fceb28c5dbe59bcfa7fe5e593bbbfb8e10cd11f1f45160311c4
debug(pam_u2f): ../util.c:110 (get_devices_from_authfile): Matched user: cromwell
debug(pam_u2f): ../util.c:137 (get_devices_from_authfile): KeyHandle for device number 1: vsmDodhUsAc7j8HfnNYcWokggFRltEb6DgwvB_02Seja55XL5k0BV9eRp9ydJZqgVIbO8hjHnm1pCJDdT7xlFQ
debug(pam_u2f): ../util.c:156 (get_devices_from_authfile): publicKey for device number 1: 041205c9eb8d0d297ee8cc82d7a592645a5d55288c5d203191ebbcee46422aca69e3cf2ee591361fceb28c5dbe59bcfa7fe5e593bbbfb8e10cd11f1f45160311c4
debug(pam_u2f): ../util.c:167 (get_devices_from_authfile): Length of key number 1 is 65
debug(pam_u2f): ../util.c:194 (get_devices_from_authfile): Found 1 device(s) for user cromwell
debug(pam_u2f): ../pam-u2f.c:295 (pam_sm_authenticate): Restored privileges
debug(pam_u2f): ../pam-u2f.c:340 (pam_sm_authenticate): Using file '/var/run/user/0/pam-u2f-authpending' for emitting touch request notifications
USB send: 00ffffffff8600089d98a5ce497607c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
USB write returned 65
now trying with timeout 2
USB read rc read 64
USB recv: ffffffff8600119d98a5ce497607c000180002020403070100000000000000000000000000000000000000000000000000000000000000000000000000000000
device /dev/hidraw1 discovered as 'Yubikey 4 OTP+U2F+CCID'
  version (Interface, Major, Minor, Build): 2, 4, 3, 7  capFlags: 1
debug(pam_u2f): ../util.c:277 (do_authentication): Device max index is 0
debug(pam_u2f): ../util.c:308 (do_authentication): Attempting authentication with device number 1
debug(pam_u2f): ../util.c:332 (do_authentication): Challenge: { "keyHandle": "vsmDodhUsAc7j8HfnNYcWokggFRltEb6DgwvB_02Seja55XL5k0BV9eRp9ydJZqgVIbO8hjHnm1pCJDdT7xlFQ", "version": "U2F_V2", "challenge": "9p4mfQSs-TJtbqoFIQj8be8gzJTjOzr3L_cbCGSbbtY", "appId": "pam:\/\/laptop" }
JSON: { "keyHandle": "vsmDodhUsAc7j8HfnNYcWokggFRltEb6DgwvB_02Seja55XL5k0BV9eRp9ydJZqgVIbO8hjHnm1pCJDdT7xlFQ", "version": "U2F_V2", "challenge": "9p4mfQSs-TJtbqoFIQj8be8gzJTjOzr3L_cbCGSbbtY", "appId": "pam:\/\/laptop" }
JSON challenge URL-B64: 9p4mfQSs-TJtbqoFIQj8be8gzJTjOzr3L_cbCGSbbtY
client data: { "challenge": "9p4mfQSs-TJtbqoFIQj8be8gzJTjOzr3L_cbCGSbbtY", "origin": "pam:\/\/laptop", "typ": "navigator.id.getAssertion" }
JSON: { "keyHandle": "vsmDodhUsAc7j8HfnNYcWokggFRltEb6DgwvB_02Seja55XL5k0BV9eRp9ydJZqgVIbO8hjHnm1pCJDdT7xlFQ", "version": "U2F_V2", "challenge": "9p4mfQSs-TJtbqoFIQj8be8gzJTjOzr3L_cbCGSbbtY", "appId": "pam:\/\/laptop" }
JSON app_id pam://laptop
JSON: { "keyHandle": "vsmDodhUsAc7j8HfnNYcWokggFRltEb6DgwvB_02Seja55XL5k0BV9eRp9ydJZqgVIbO8hjHnm1pCJDdT7xlFQ", "version": "U2F_V2", "challenge": "9p4mfQSs-TJtbqoFIQj8be8gzJTjOzr3L_cbCGSbbtY", "appId": "pam:\/\/laptop" }
JSON keyHandle URL-B64: vsmDodhUsAc7j8HfnNYcWokggFRltEb6DgwvB_02Seja55XL5k0BV9eRp9ydJZqgVIbO8hjHnm1pCJDdT7xlFQ
USB send: 000018000283008a00020700000081330dfd388a6376c74e1a060c57f4a67a180e9de6cec9b6c85a72486d48995705a9a12dac5883bc1247c0646b263e008ed6
USB write returned 65
USB send: 000018000200963cf7da28a181ce80e25874fa9540bec983a1d854b0073b8fc1df9cd61c5a8920805465b446fa0e0c2f07fd3649e8dae795cbe64d0157d791a7
USB write returned 65
USB send: 0000180002019d259aa05486cef218c79e6d690890dd4fbc65150000000000000000000000000000000000000000000000000000000000000000000000000000
USB write returned 65
now trying with timeout 2
now trying with timeout 4
now trying with timeout 8
now trying with timeout 16
USB read rc read 64
USB recv: 00180002830002698500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
USB data (len 2): 6985
Please touch the device.
JSON: { "keyHandle": "vsmDodhUsAc7j8HfnNYcWokggFRltEb6DgwvB_02Seja55XL5k0BV9eRp9ydJZqgVIbO8hjHnm1pCJDdT7xlFQ", "version": "U2F_V2", "challenge": "9p4mfQSs-TJtbqoFIQj8be8gzJTjOzr3L_cbCGSbbtY", "appId": "pam:\/\/laptop" }
JSON challenge URL-B64: 9p4mfQSs-TJtbqoFIQj8be8gzJTjOzr3L_cbCGSbbtY
client data: { "challenge": "9p4mfQSs-TJtbqoFIQj8be8gzJTjOzr3L_cbCGSbbtY", "origin": "pam:\/\/laptop", "typ": "navigator.id.getAssertion" }
JSON: { "keyHandle": "vsmDodhUsAc7j8HfnNYcWokggFRltEb6DgwvB_02Seja55XL5k0BV9eRp9ydJZqgVIbO8hjHnm1pCJDdT7xlFQ", "version": "U2F_V2", "challenge": "9p4mfQSs-TJtbqoFIQj8be8gzJTjOzr3L_cbCGSbbtY", "appId": "pam:\/\/laptop" }
JSON app_id pam://laptop
JSON: { "keyHandle": "vsmDodhUsAc7j8HfnNYcWokggFRltEb6DgwvB_02Seja55XL5k0BV9eRp9ydJZqgVIbO8hjHnm1pCJDdT7xlFQ", "version": "U2F_V2", "challenge": "9p4mfQSs-TJtbqoFIQj8be8gzJTjOzr3L_cbCGSbbtY", "appId": "pam:\/\/laptop" }
JSON keyHandle URL-B64: vsmDodhUsAc7j8HfnNYcWokggFRltEb6DgwvB_02Seja55XL5k0BV9eRp9ydJZqgVIbO8hjHnm1pCJDdT7xlFQ
USB send: 000018000283008a00020300000081330dfd388a6376c74e1a060c57f4a67a180e9de6cec9b6c85a72486d48995705a9a12dac5883bc1247c0646b263e008ed6
USB write returned 65
USB send: 000018000200963cf7da28a181ce80e25874fa9540bec983a1d854b0073b8fc1df9cd61c5a8920805465b446fa0e0c2f07fd3649e8dae795cbe64d0157d791a7
USB write returned 65
USB send: 0000180002019d259aa05486cef218c79e6d690890dd4fbc65150000000000000000000000000000000000000000000000000000000000000000000000000000
USB write returned 65
now trying with timeout 2
now trying with timeout 4
now trying with timeout 8
now trying with timeout 16
USB read rc read 64
USB recv: 00180002830002698500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
USB data (len 2): 6985
USB send: 000018000283008a00020300000081330dfd388a6376c74e1a060c57f4a67a180e9de6cec9b6c85a72486d48995705a9a12dac5883bc1247c0646b263e008ed6
USB write returned 65
USB send: 000018000200963cf7da28a181ce80e25874fa9540bec983a1d854b0073b8fc1df9cd61c5a8920805465b446fa0e0c2f07fd3649e8dae795cbe64d0157d791a7
USB write returned 65
USB send: 0000180002019d259aa05486cef218c79e6d690890dd4fbc65150000000000000000000000000000000000000000000000000000000000000000000000000000
USB write returned 65
now trying with timeout 2
now trying with timeout 4
now trying with timeout 8
USB read rc read 64
USB recv: 00180002830002698500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
USB data (len 2): 6985
USB send: 000018000283008a00020300000081330dfd388a6376c74e1a060c57f4a67a180e9de6cec9b6c85a72486d48995705a9a12dac5883bc1247c0646b263e008ed6
USB write returned 65
USB send: 000018000200963cf7da28a181ce80e25874fa9540bec983a1d854b0073b8fc1df9cd61c5a8920805465b446fa0e0c2f07fd3649e8dae795cbe64d0157d791a7
USB write returned 65
USB send: 0000180002019d259aa05486cef218c79e6d690890dd4fbc65150000000000000000000000000000000000000000000000000000000000000000000000000000
USB write returned 65
now trying with timeout 2
now trying with timeout 4
now trying with timeout 8
now trying with timeout 16
now trying with timeout 32
now trying with timeout 64
USB read rc read 64
USB recv: 0018000283004f01000000a0304602210099dad89f731dc1da6dfaecd9c59dbe1b38d8e0b9e5ff89351ee7e10b75b875de02210084f1064ad6087645168b856a
now trying with timeout 2
now trying with timeout 4
now trying with timeout 8
now trying with timeout 16
USB read rc read 64
USB recv: 0018000200229e8b557e14ed7a6ac8e592d838c180ebe120a2900000000000000000000000000000000000000000000000000000000000000000000000000000
USB data (len 79): 01000000a0304602210099dad89f731dc1da6dfaecd9c59dbe1b38d8e0b9e5ff89351ee7e10b75b875de02210084f1064ad6087645168b856a229e8b557e14ed7a6ac8e592d838c180ebe120a29000
JSON: { "keyHandle": "vsmDodhUsAc7j8HfnNYcWokggFRltEb6DgwvB_02Seja55XL5k0BV9eRp9ydJZqgVIbO8hjHnm1pCJDdT7xlFQ", "version": "U2F_V2", "challenge": "9p4mfQSs-TJtbqoFIQj8be8gzJTjOzr3L_cbCGSbbtY", "appId": "pam:\/\/laptop" }
JSON keyHandle URL-B64: vsmDodhUsAc7j8HfnNYcWokggFRltEb6DgwvB_02Seja55XL5k0BV9eRp9ydJZqgVIbO8hjHnm1pCJDdT7xlFQ
debug(pam_u2f): ../util.c:349 (do_authentication): Response: { "signatureData": "AQAAAKAwRgIhAJna2J9zHcHabfrs2cWdvhs42OC55f-JNR7n4Qt1uHXeAiEAhPEGStYIdkUWi4VqIp6LVX4U7XpqyOWS2DjBgOvhIKI", "clientData": "eyAiY2hhbGxlbmdlIjogIjlwNG1mUVNzLVRKdGJxb0ZJUWo4YmU4Z3pKVGpPenIzTF9jYkNHU2JidFkiLCAib3JpZ2luIjogInBhbTpcL1wvZGViaWFuIiwgInR5cCI6ICJuYXZpZ2F0b3IuaWQuZ2V0QXNzZXJ0aW9uIiB9", "keyHandle": "vsmDodhUsAc7j8HfnNYcWokggFRltEb6DgwvB_02Seja55XL5k0BV9eRp9ydJZqgVIbO8hjHnm1pCJDdT7xlFQ" }
signatureData: AQAAAKAwRgIhAJna2J9zHcHabfrs2cWdvhs42OC55f-JNR7n4Qt1uHXeAiEAhPEGStYIdkUWi4VqIp6LVX4U7XpqyOWS2DjBgOvhIKI
clientData: eyAiY2hhbGxlbmdlIjogIjlwNG1mUVNzLVRKdGJxb0ZJUWo4YmU4Z3pKVGpPenIzTF9jYkNHU2JidFkiLCAib3JpZ2luIjogInBhbTpcL1wvZGViaWFuIiwgInR5cCI6ICJuYXZpZ2F0b3IuaWQuZ2V0QXNzZXJ0aW9uIiB9
keyHandle: vsmDodhUsAc7j8HfnNYcWokggFRltEb6DgwvB_02Seja55XL5k0BV9eRp9ydJZqgVIbO8hjHnm1pCJDdT7xlFQ
signatureData Hex: 
01 00 00 00 a0 30 46 02 21 00 99 da d8 9f 73 1d 
c1 da 6d fa ec d9 c5 9d be 1b 38 d8 e0 b9 e5 ff 
89 35 1e e7 e1 0b 75 b8 75 de 02 21 00 84 f1 06 
4a d6 08 76 45 16 8b 85 6a 22 9e 8b 55 7e 14 ed 
7a 6a c8 e5 92 d8 38 c1 80 eb e1 20 a2 
clientData: { "challenge": "9p4mfQSs-TJtbqoFIQj8be8gzJTjOzr3L_cbCGSbbtY", "origin": "pam:\/\/laptop", "typ": "navigator.id.getAssertion" }
debug(pam_u2f): ../pam-u2f.c:410 (pam_sm_authenticate): done. [Success]
Linux laptop 4.19.0-14-amd64 #1 SMP Debian 4.19.171-2 (2021-01-30) x86_64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
cromwell@laptop:~$ exit
# exit
Script done, file is u2f-debug-output

Troubleshooting

This should be very easy to set up, but simple mistakes happen. For a troubleshooting checklist:

If you still haven't noticed what's wrong, turn on the debug option and capture output, as shown above.

If the user's file is in the wrong place you will see something like the following. Note that from here forward, I have manually added color to highlight the diagnostic output, the PAM module doesn't make it this easy for you:

[...lines deleted...]
debug(pam_u2f): ../pam-u2f.c:210 (pam_sm_authenticate): Requesting authentication for user cromwell
debug(pam_u2f): ../pam-u2f.c:221 (pam_sm_authenticate): Found user cromwell
debug(pam_u2f): ../pam-u2f.c:222 (pam_sm_authenticate): Home directory for cromwell is /home/cromwell
debug(pam_u2f): ../pam-u2f.c:229 (pam_sm_authenticate): Variable XDG_CONFIG_HOME is not set. Using default value ($HOME/.config/)
debug(pam_u2f): ../pam-u2f.c:265 (pam_sm_authenticate): Using authentication file /home/cromwell/.config/Yubico/u2f_keys
debug(pam_u2f): ../pam-u2f.c:278 (pam_sm_authenticate): Dropping privileges
debug(pam_u2f): ../pam-u2f.c:284 (pam_sm_authenticate): Switched to uid 1001
debug(pam_u2f): ../util.c:42 (get_devices_from_authfile): Cannot open file: /home/cromwell/.config/Yubico/u2f_keys (No such file or directory)
debug(pam_u2f): ../pam-u2f.c:295 (pam_sm_authenticate): Restored privileges
debug(pam_u2f): ../pam-u2f.c:310 (pam_sm_authenticate): Unable to get devices from file /home/cromwell/.config/Yubico/u2f_keys
debug(pam_u2f): ../pam-u2f.c:410 (pam_sm_authenticate): done. [Authentication service cannot retrieve authentication info]
[...lines deleted...]

If there's a file in the right place for the user but it contains the wrong name, you will see something like the following:

[...lines deleted...]
debug(pam_u2f): ../pam-u2f.c:210 (pam_sm_authenticate): Requesting authentication for user cromwell
debug(pam_u2f): ../pam-u2f.c:221 (pam_sm_authenticate): Found user cromwell
debug(pam_u2f): ../pam-u2f.c:222 (pam_sm_authenticate): Home directory for cromwell is /home/cromwell
debug(pam_u2f): ../pam-u2f.c:229 (pam_sm_authenticate): Variable XDG_CONFIG_HOME is not set. Using default value ($HOME/.config/)
debug(pam_u2f): ../pam-u2f.c:265 (pam_sm_authenticate): Using authentication file /home/cromwell/.config/Yubico/u2f_keys
debug(pam_u2f): ../pam-u2f.c:278 (pam_sm_authenticate): Dropping privileges
debug(pam_u2f): ../pam-u2f.c:284 (pam_sm_authenticate): Switched to uid 1001
debug(pam_u2f): ../util.c:105 (get_devices_from_authfile): Authorization line: root:NyHjaySH8f9z8Z1BF5L6y04Bwp1UYbh1vMdGSm-FraPWxXriARptEYQYLI8m7EDqp8rfFyzl8mvtK5yftoVu_Q,04df67960d7d9119cd2c56f57a7d40bbc3eee08a7f01bec0e0923b00e4a2b5eb764b9c1c7fb4d25c0f513498c7a2fe77594a61310d5e8a79d68ce1b3d17de7ed4
debug(pam_u2f): ../util.c:194 (get_devices_from_authfile): Found 0 device(s) for user cromwell
debug(pam_u2f): ../pam-u2f.c:295 (pam_sm_authenticate): Restored privileges
debug(pam_u2f): ../pam-u2f.c:314 (pam_sm_authenticate): Found no devices. Aborting.
[...lines deleted...]

If there's a file in the right place with the right name, but the wrong origin (that is, host name), you will see something like the following. This will appear further down the output than the above examples, only appearing after you press the blinking button. It is only then that the device generates the signature, which includes the origin associated with the key:

[...lines deleted...]
debug(pam_u2f): ../util.c:368 (do_authentication): Device for this keyhandle is not present
USB send: 00001700038100010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
USB write returned 65
now trying with timeout 2
USB read rc read 64
USB recv: 00170003810001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
debug(pam_u2f): ../pam-u2f.c:371 (pam_sm_authenticate): do_authentication returned -2
debug(pam_u2f): ../pam-u2f.c:410 (pam_sm_authenticate): done. [Authentication failure]

Suggestion: To make the authentication portable across several systems, you might generate the user files specifying a site-wide origin. Then specify that same origin in the PAM configuration:

# ( pamu2fcfg --origin=pam://headquarters --username=cromwell ; echo ) > ~cromwell/.config/Yubico/u2f_keys
# grep pam_u2f.so /etc/pam.d/common-auth
auth	required	pam_u2f.so cue origin=pam://headquarters

Going Deeper: Verbose Registration

To see more of what's happening, add the --debug option. The hostname is already set to laptop so we don't really need to specify the origin or application ID.

You will see that the device returns its certificate.

The block "registrationData Hex" just before the certificate is what the device has generated for this event. It created a new key pair based on the random seed sent from the application, and then created a certificate containing that public key and the origin inside. That certificate was signed by the device key, for which we have a certificate of its public key signed by the manufacturer. So there's your trust chain.

# pamu2fcfg --username=cromwell --debug ; echo
USB send: 00ffffffff8600089c25f6f7538d23ea000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
USB write returned 65
now trying with timeout 2
USB read rc read 64
USB recv: ffffffff8600119c25f6f7538d23ea00150003020403070100000000000000000000000000000000000000000000000000000000000000000000000000000000
device /dev/hidraw1 discovered as 'Yubikey 4 OTP+U2F+CCID'
  version (Interface, Major, Minor, Build): 2, 4, 3, 7  capFlags: 1
JSON: { "challenge": "Xp9t3n9mZql9Q-TvnToX41Awz_60pqTu4rlozqBrw60", "version": "U2F_V2", "appId": "pam:\/\/laptop" }
JSON challenge URL-B64: Xp9t3n9mZql9Q-TvnToX41Awz_60pqTu4rlozqBrw60
client data: { "challenge": "Xp9t3n9mZql9Q-TvnToX41Awz_60pqTu4rlozqBrw60", "origin": "pam:\/\/laptop", "typ": "navigator.id.finishEnrollment" }
JSON: { "challenge": "Xp9t3n9mZql9Q-TvnToX41Awz_60pqTu4rlozqBrw60", "version": "U2F_V2", "appId": "pam:\/\/laptop" }
JSON app_id pam://laptop
USB send: 000015000383004900010300000040efa1f4e3791e219fd680508355875773defabe421f4413a58a7098cfae85a8b1a9a12dac5883bc1247c0646b263e008ed6
USB write returned 65
USB send: 000015000300963cf7da28a181ce80e25874fa950000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
USB write returned 65
now trying with timeout 2
USB read rc read 64
USB recv: 00150003830002698500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
USB data (len 2): 6985
USB send: 000015000383004900010300000040efa1f4e3791e219fd680508355875773defabe421f4413a58a7098cfae85a8b1a9a12dac5883bc1247c0646b263e008ed6
USB write returned 65
USB send: 000015000300963cf7da28a181ce80e25874fa950000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
USB write returned 65
now trying with timeout 2
USB read rc read 64
USB recv: 00150003830002698500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
USB data (len 2): 6985
USB send: 000015000383004900010300000040efa1f4e3791e219fd680508355875773defabe421f4413a58a7098cfae85a8b1a9a12dac5883bc1247c0646b263e008ed6
USB write returned 65
USB send: 000015000300963cf7da28a181ce80e25874fa950000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
USB write returned 65
now trying with timeout 2
now trying with timeout 4
now trying with timeout 8
now trying with timeout 16
now trying with timeout 32
now trying with timeout 64
now trying with timeout 128
USB read rc read 64
USB recv: 0015000383031f050471576ddf3e14162c93a7eab869b9478b3147b157e42d2c8c10a73d749407516ab1a4c40b75141b6187ff18143672c95f5dee2cc009cd1d
now trying with timeout 2
now trying with timeout 4
now trying with timeout 8
now trying with timeout 16
now trying with timeout 32
USB read rc read 64
USB recv: 0015000300fd1fe67e20242181fd40f5ef692acb68c427b91956484b7660e9c91944c133943e36a519c898490c6f9f627f1df6738e0d57ba3c8b498b0ce1ac85
now trying with timeout 2
now trying with timeout 4
USB read rc read 64
USB recv: 0015000301fc821581a87b6c569541ee79eb5e333082024f30820137a00302010202040d000b16300d06092a864886f70d01010b0500302e312c302a06035504
now trying with timeout 2
now trying with timeout 4
USB read rc read 64
USB recv: 001500030203132359756269636f2055324620526f6f742043412053657269616c203435373230303633313020170d3134303830313030303030305a180f3230
now trying with timeout 2
now trying with timeout 4
USB read rc read 64
USB recv: 00150003033530303930343030303030305a3031312f302d06035504030c2659756269636f205532462045452053657269616c20323339323537333430313537
now trying with timeout 2
USB read rc read 64
USB recv: 001500030436353237303059301306072a8648ce3d020106082a8648ce3d030107034200044cacfa6ed104ba194bd6e066d7e13fcc6a600f10d2485c7ea3dbd4
now trying with timeout 2
USB read rc read 64
USB recv: 00150003054cd0d50db251387ba3bd1ebae6dee6250a0558c6e9be6118a4438e5a435f1ed2eb0ce8bb85a33b3039302206092b0601040182c40a020415312e33
now trying with timeout 2
USB read rc read 64
USB recv: 00150003062e362e312e342e312e34313438322e312e353013060b2b0601040182e51c020101040403020520300d06092a864886f70d01010b05000382010100
now trying with timeout 2
USB read rc read 64
USB recv: 00150003078ec24da8819582e73084199c9f140afaea805ba29fcd024d3e14022196b01c21d1e63e0914b02f82c415921390b9456323ac7cc0e523ba1d75237f
now trying with timeout 2
USB read rc read 64
USB recv: 00150003082669fc1f3acf5afcca54fffe982b91312773ef7e7014d617e7195ef8d2e4a1cb598f21ce0aa75de01f25817d27cf03623d9b9ffac758e5f87384b4
now trying with timeout 2
USB read rc read 64
USB recv: 001500030966b5ba5f0434e84cfe7bb4b4795a5218ea427a40a79ca59e6c54dc42cd2571467700a6d655ed84ac5f6c1ed392ade661e4047aa18b90933d042638
now trying with timeout 2
now trying with timeout 4
USB read rc read 64
USB recv: 001500030ae6c7a2fedc07ee2ae42a6e7c3cc40454ca3cbded5b157a1ef42bd09e8ca7a6d91480aae674cfed53dab679c97a5440f5598f4a942e2e3a51aa9245
now trying with timeout 2
now trying with timeout 4
USB read rc read 64
USB recv: 001500030b291a1b8fc790f72baf7971bfeeebad04ecc11d6f3045022100b604d9ae8190ddc136b3fe7700b3a7f805c898330f7d13ba3fce7ea4390b37650220
now trying with timeout 2
USB read rc read 64
USB recv: 001500030c4948abcedb0f1ada2e61a9eab45bdf616e27d42945fe1bc368c2173ee62cf404900000000000000000000000000000000000000000000000000000
USB data (len 799): 050471576ddf3e14162c93a7eab869b9478b3147b157e42d2c8c10a73d749407516ab1a4c40b75141b6187ff18143672c95f5dee2cc009cd1dfd1fe67e20242181fd40f5ef692acb68c427b91956484b7660e9c91944c133943e36a519c898490c6f9f627f1df6738e0d57ba3c8b498b0ce1ac85fc821581a87b6c569541ee79eb5e333082024f30820137a00302010202040d000b16300d06092a864886f70d01010b0500302e312c302a0603550403132359756269636f2055324620526f6f742043412053657269616c203435373230303633313020170d3134303830313030303030305a180f32303530303930343030303030305a3031312f302d06035504030c2659756269636f205532462045452053657269616c2032333932353733343031353736353237303059301306072a8648ce3d020106082a8648ce3d030107034200044cacfa6ed104ba194bd6e066d7e13fcc6a600f10d2485c7ea3dbd44cd0d50db251387ba3bd1ebae6dee6250a0558c6e9be6118a4438e5a435f1ed2eb0ce8bb85a33b3039302206092b0601040182c40a020415312e332e362e312e342e312e34313438322e312e353013060b2b0601040182e51c020101040403020520300d06092a864886f70d01010b050003820101008ec24da8819582e73084199c9f140afaea805ba29fcd024d3e14022196b01c21d1e63e0914b02f82c415921390b9456323ac7cc0e523ba1d75237f2669fc1f3acf5afcca54fffe982b91312773ef7e7014d617e7195ef8d2e4a1cb598f21ce0aa75de01f25817d27cf03623d9b9ffac758e5f87384b466b5ba5f0434e84cfe7bb4b4795a5218ea427a40a79ca59e6c54dc42cd2571467700a6d655ed84ac5f6c1ed392ade661e4047aa18b90933d042638e6c7a2fedc07ee2ae42a6e7c3cc40454ca3cbded5b157a1ef42bd09e8ca7a6d91480aae674cfed53dab679c97a5440f5598f4a942e2e3a51aa9245291a1b8fc790f72baf7971bfeeebad04ecc11d6f3045022100b604d9ae8190ddc136b3fe7700b3a7f805c898330f7d13ba3fce7ea4390b376502204948abcedb0f1ada2e61a9eab45bdf616e27d42945fe1bc368c2173ee62cf4049000
registrationData: BQRxV23fPhQWLJOn6rhpuUeLMUexV-QtLIwQpz10lAdRarGkxAt1FBthh_8YFDZyyV9d7izACc0d_R_mfiAkIYH9QPXvaSrLaMQnuRlWSEt2YOnJGUTBM5Q-NqUZyJhJDG-fYn8d9nOODVe6PItJiwzhrIX8ghWBqHtsVpVB7nnrXjMwggJPMIIBN6ADAgECAgQNAAsWMA0GCSqGSIb3DQEBCwUAMC4xLDAqBgNVBAMTI1l1YmljbyBVMkYgUm9vdCBDQSBTZXJpYWwgNDU3MjAwNjMxMCAXDTE0MDgwMTAwMDAwMFoYDzIwNTAwOTA0MDAwMDAwWjAxMS8wLQYDVQQDDCZZdWJpY28gVTJGIEVFIFNlcmlhbCAyMzkyNTczNDAxNTc2NTI3MDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABEys-m7RBLoZS9bgZtfhP8xqYA8Q0khcfqPb1EzQ1Q2yUTh7o70euube5iUKBVjG6b5hGKRDjlpDXx7S6wzou4WjOzA5MCIGCSsGAQQBgsQKAgQVMS4zLjYuMS40LjEuNDE0ODIuMS41MBMGCysGAQQBguUcAgEBBAQDAgUgMA0GCSqGSIb3DQEBCwUAA4IBAQCOwk2ogZWC5zCEGZyfFAr66oBbop_NAk0-FAIhlrAcIdHmPgkUsC-CxBWSE5C5RWMjrHzA5SO6HXUjfyZp_B86z1r8ylT__pgrkTEnc-9-cBTWF-cZXvjS5KHLWY8hzgqnXeAfJYF9J88DYj2bn_rHWOX4c4S0ZrW6XwQ06Ez-e7S0eVpSGOpCekCnnKWebFTcQs0lcUZ3AKbWVe2ErF9sHtOSreZh5AR6oYuQkz0EJjjmx6L-3AfuKuQqbnw8xARUyjy97VsVeh70K9CejKem2RSAquZ0z-1T2rZ5yXpUQPVZj0qULi46UaqSRSkaG4_HkPcrr3lxv-7rrQTswR1vMEUCIQC2BNmugZDdwTaz_ncAs6f4BciYMw99E7o_zn6kOQs3ZQIgSUirztsPGtouYanqtFvfYW4n1ClF_hvDaMIXPuYs9AQ
clientData: eyAiY2hhbGxlbmdlIjogIlhwOXQzbjltWnFsOVEtVHZuVG9YNDFBd3pfNjBwcVR1NHJsb3pxQnJ3NjAiLCAib3JpZ2luIjogInBhbTpcL1wvZGViaWFuIiwgInR5cCI6ICJuYXZpZ2F0b3IuaWQuZmluaXNoRW5yb2xsbWVudCIgfQ
registrationData Hex: 
05 04 71 57 6d df 3e 14 16 2c 93 a7 ea b8 69 b9 
47 8b 31 47 b1 57 e4 2d 2c 8c 10 a7 3d 74 94 07 
51 6a b1 a4 c4 0b 75 14 1b 61 87 ff 18 14 36 72 
c9 5f 5d ee 2c c0 09 cd 1d fd 1f e6 7e 20 24 21 
81 fd 40 f5 ef 69 2a cb 68 c4 27 b9 19 56 48 4b 
76 60 e9 c9 19 44 c1 33 94 3e 36 a5 19 c8 98 49 
0c 6f 9f 62 7f 1d f6 73 8e 0d 57 ba 3c 8b 49 8b 
0c e1 ac 85 fc 82 15 81 a8 7b 6c 56 95 41 ee 79 
eb 5e 33 30 82 02 4f 30 82 01 37 a0 03 02 01 02 
02 04 0d 00 0b 16 30 0d 06 09 2a 86 48 86 f7 0d 
01 01 0b 05 00 30 2e 31 2c 30 2a 06 03 55 04 03 
13 23 59 75 62 69 63 6f 20 55 32 46 20 52 6f 6f 
74 20 43 41 20 53 65 72 69 61 6c 20 34 35 37 32 
30 30 36 33 31 30 20 17 0d 31 34 30 38 30 31 30 
30 30 30 30 30 5a 18 0f 32 30 35 30 30 39 30 34 
30 30 30 30 30 30 5a 30 31 31 2f 30 2d 06 03 55 
04 03 0c 26 59 75 62 69 63 6f 20 55 32 46 20 45 
45 20 53 65 72 69 61 6c 20 32 33 39 32 35 37 33 
34 30 31 35 37 36 35 32 37 30 30 59 30 13 06 07 
2a 86 48 ce 3d 02 01 06 08 2a 86 48 ce 3d 03 01 
07 03 42 00 04 4c ac fa 6e d1 04 ba 19 4b d6 e0 
66 d7 e1 3f cc 6a 60 0f 10 d2 48 5c 7e a3 db d4 
4c d0 d5 0d b2 51 38 7b a3 bd 1e ba e6 de e6 25 
0a 05 58 c6 e9 be 61 18 a4 43 8e 5a 43 5f 1e d2 
eb 0c e8 bb 85 a3 3b 30 39 30 22 06 09 2b 06 01 
04 01 82 c4 0a 02 04 15 31 2e 33 2e 36 2e 31 2e 
34 2e 31 2e 34 31 34 38 32 2e 31 2e 35 30 13 06 
0b 2b 06 01 04 01 82 e5 1c 02 01 01 04 04 03 02 
05 20 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 
00 03 82 01 01 00 8e c2 4d a8 81 95 82 e7 30 84 
19 9c 9f 14 0a fa ea 80 5b a2 9f cd 02 4d 3e 14 
02 21 96 b0 1c 21 d1 e6 3e 09 14 b0 2f 82 c4 15 
92 13 90 b9 45 63 23 ac 7c c0 e5 23 ba 1d 75 23 
7f 26 69 fc 1f 3a cf 5a fc ca 54 ff fe 98 2b 91 
31 27 73 ef 7e 70 14 d6 17 e7 19 5e f8 d2 e4 a1 
cb 59 8f 21 ce 0a a7 5d e0 1f 25 81 7d 27 cf 03 
62 3d 9b 9f fa c7 58 e5 f8 73 84 b4 66 b5 ba 5f 
04 34 e8 4c fe 7b b4 b4 79 5a 52 18 ea 42 7a 40 
a7 9c a5 9e 6c 54 dc 42 cd 25 71 46 77 00 a6 d6 
55 ed 84 ac 5f 6c 1e d3 92 ad e6 61 e4 04 7a a1 
8b 90 93 3d 04 26 38 e6 c7 a2 fe dc 07 ee 2a e4 
2a 6e 7c 3c c4 04 54 ca 3c bd ed 5b 15 7a 1e f4 
2b d0 9e 8c a7 a6 d9 14 80 aa e6 74 cf ed 53 da 
b6 79 c9 7a 54 40 f5 59 8f 4a 94 2e 2e 3a 51 aa 
92 45 29 1a 1b 8f c7 90 f7 2b af 79 71 bf ee eb 
ad 04 ec c1 1d 6f 30 45 02 21 00 b6 04 d9 ae 81 
90 dd c1 36 b3 fe 77 00 b3 a7 f8 05 c8 98 33 0f 
7d 13 ba 3f ce 7e a4 39 0b 37 65 02 20 49 48 ab 
ce db 0f 1a da 2e 61 a9 ea b4 5b df 61 6e 27 d4 
29 45 fe 1b c3 68 c2 17 3e e6 2c f4 04 
Key handle length: 64
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 218106646 (0xd000b16)
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: CN=Yubico U2F Root CA Serial 457200631
        Validity
            Not Before: Aug  1 00:00:00 2014 GMT
            Not After : Sep  4 00:00:00 2050 GMT
        Subject: CN=Yubico U2F EE Serial 23925734015765270
        Subject Public Key Info:
            Public Key Algorithm: id-ecPublicKey
                Public-Key: (256 bit)
                pub:
                    04:4c:ac:fa:6e:d1:04:ba:19:4b:d6:e0:66:d7:e1:
                    3f:cc:6a:60:0f:10:d2:48:5c:7e:a3:db:d4:4c:d0:
                    d5:0d:b2:51:38:7b:a3:bd:1e:ba:e6:de:e6:25:0a:
                    05:58:c6:e9:be:61:18:a4:43:8e:5a:43:5f:1e:d2:
                    eb:0c:e8:bb:85
                ASN1 OID: prime256v1
                NIST CURVE: P-256
        X509v3 extensions:
            1.3.6.1.4.1.41482.2: 
                1.3.6.1.4.1.41482.1.5
            1.3.6.1.4.1.45724.2.1.1: 
                ... 
    Signature Algorithm: sha256WithRSAEncryption
         8e:c2:4d:a8:81:95:82:e7:30:84:19:9c:9f:14:0a:fa:ea:80:
         5b:a2:9f:cd:02:4d:3e:14:02:21:96:b0:1c:21:d1:e6:3e:09:
         14:b0:2f:82:c4:15:92:13:90:b9:45:63:23:ac:7c:c0:e5:23:
         ba:1d:75:23:7f:26:69:fc:1f:3a:cf:5a:fc:ca:54:ff:fe:98:
         2b:91:31:27:73:ef:7e:70:14:d6:17:e7:19:5e:f8:d2:e4:a1:
         cb:59:8f:21:ce:0a:a7:5d:e0:1f:25:81:7d:27:cf:03:62:3d:
         9b:9f:fa:c7:58:e5:f8:73:84:b4:66:b5:ba:5f:04:34:e8:4c:
         fe:7b:b4:b4:79:5a:52:18:ea:42:7a:40:a7:9c:a5:9e:6c:54:
         dc:42:cd:25:71:46:77:00:a6:d6:55:ed:84:ac:5f:6c:1e:d3:
         92:ad:e6:61:e4:04:7a:a1:8b:90:93:3d:04:26:38:e6:c7:a2:
         fe:dc:07:ee:2a:e4:2a:6e:7c:3c:c4:04:54:ca:3c:bd:ed:5b:
         15:7a:1e:f4:2b:d0:9e:8c:a7:a6:d9:14:80:aa:e6:74:cf:ed:
         53:da:b6:79:c9:7a:54:40:f5:59:8f:4a:94:2e:2e:3a:51:aa:
         92:45:29:1a:1b:8f:c7:90:f7:2b:af:79:71:bf:ee:eb:ad:04:
         ec:c1:1d:6f
-----BEGIN CERTIFICATE-----
MIICTzCCATegAwIBAgIEDQALFjANBgkqhkiG9w0BAQsFADAuMSwwKgYDVQQDEyNZ
dWJpY28gVTJGIFJvb3QgQ0EgU2VyaWFsIDQ1NzIwMDYzMTAgFw0xNDA4MDEwMDAw
MDBaGA8yMDUwMDkwNDAwMDAwMFowMTEvMC0GA1UEAwwmWXViaWNvIFUyRiBFRSBT
ZXJpYWwgMjM5MjU3MzQwMTU3NjUyNzAwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNC
AARMrPpu0QS6GUvW4GbX4T/MamAPENJIXH6j29RM0NUNslE4e6O9Hrrm3uYlCgVY
xum+YRikQ45aQ18e0usM6LuFozswOTAiBgkrBgEEAYLECgIEFTEuMy42LjEuNC4x
LjQxNDgyLjEuNTATBgsrBgEEAYLlHAIBAQQEAwIFIDANBgkqhkiG9w0BAQsFAAOC
AQEAjsJNqIGVgucwhBmcnxQK+uqAW6KfzQJNPhQCIZawHCHR5j4JFLAvgsQVkhOQ
uUVjI6x8wOUjuh11I38mafwfOs9a/MpU//6YK5ExJ3PvfnAU1hfnGV740uShy1mP
Ic4Kp13gHyWBfSfPA2I9m5/6x1jl+HOEtGa1ul8ENOhM/nu0tHlaUhjqQnpAp5yl
nmxU3ELNJXFGdwCm1lXthKxfbB7Tkq3mYeQEeqGLkJM9BCY45sei/twH7irkKm58
PMQEVMo8ve1bFXoe9CvQnoynptkUgKrmdM/tU9q2ecl6VED1WY9KlC4uOlGqkkUp
GhuPx5D3K695cb/u660E7MEdbw==
-----END CERTIFICATE-----
clientData: { "challenge": "Xp9t3n9mZql9Q-TvnToX41Awz_60pqTu4rlozqBrw60", "origin": "pam:\/\/laptop", "typ": "navigator.id.finishEnrollment" }
cromwell:9e9pKstoxCe5GVZIS3Zg6ckZRMEzlD42pRnImEkMb59ifx32c44NV7o8i0mLDOGshfyCFYGoe2xWlUHueeteMw,0471576ddf3e14162c93a7eab869b9478b3147b157e42d2c8c10a73d749407516ab1a4c40b75141b6187ff18143672c95f5dee2cc009cd1dfd1fe67e20242181fd