Using Nitrokey Pro and Fido2

In order to store and protect my credentials and to simplify 2 Factor authentication I’ve bought some USB keys from Nitrokey.

While it may be possible to find more complete or fancy solutions I selected Nitrokey, a German company, as both hardware and software is Open Source and I trust this way more than a black box provided by a company that is asking to get some blind trust.

For storing and protecting GPG or S/MIME key I’ve choosed a Nitrokey Pro 2 USB key.

For simplifying authentication I’ve also selected a Nitrokey FIDO2), it can be use for passwordless authentication (FIDO2) or as as a second authentification factor (U2F).

I will be using mainly on my GNU/Linux Archlinux personal desktop and on my work MacOS X laptop. I may also try it on Windows 10.

I will be using my existing personal GPG key and my work S/MIME certificate from Sectito and part of the Interoperable Global Trust Federation IGTF, as since years (decades in fact :) ) an X509-based Public Key Infrastructure (PKI) is used to identify and authorize access to the computing and storage resources. More and more services are now doing Federated authentication via OpenID Connect and SAML 2.0, but X509 certificates will be there for some more time. If you want to learn a bit about the European EGI distributed infrastructure supporting scientific computing you can start at EGI.

My first intent is to make use of the Nitrokey Pro 2 to sign my messages using mutt (what else?). As said my personal messages are signed using my PGP/GPG key, and my work emails are signed using my S/MIME certificate.

In case you don’t already have a GPG key you can create one on your comupter and then import it in the Nitrokey, thus allowing you to backup it elsewhere. Nitrokey provide a clean documentation about generating your GPG key. I also put together some notes/links in a gist.

I also want to use the Nitrokey FIDO2 to protect access to my BitWarden password manager - BitWarden is similar to LastPass or 1password, but it’s Open Source and you can host the synchronisation server on premise if needed. I highly recommned using BitWarden too.

Using the Nitrokey Pro 2 with S/MIME

According to Nitrokey Pro 2 documentation for S/MIME it’s required to install OpenSC. According to the Archlinux wiki, pcsc and ccid can help.

They can be installed from the community repository:

❯ trizen -S opensc pcsc-tools ccid

Then edit /etc/opensc.conf to appen enable_pinpad = false in the configuration block and start pcscd.service:

❯ sudo systemctl start pcscd.service

The smart card should show up:

❯ openpgp-tool -C -K
Using reader with a card: Nitrokey Nitrokey Pro (0000000000000000000(...)16) 00 00
AID:             d2:76:00:01:24:01:(...):00:00:80:16:00:00
Version:         3.3
Manufacturer:    ZeitControl
Serial number:   00(...)16
Aut Algorithm:   RSA4096
Aut Create Date: 2020-07-09 16:39:14
Aut Fingerprint: 9e:4a:04:77:6b:6d:36:(...):5c:70:11:5e:f0:57:e3
Dec Algorithm:   RSA4096
Dec Create Date: 2020-07-09 16:37:12
Dec Fingerprint: f3:67:ba:47:cd:ed:90:(...):1b:14:a2:b2:22:c2:11:ac:0d
Sig Algorithm:   RSA4096
Sig Create Date: 2020-07-09 16:38:47
Sig Fingerprint: 3f:e2:db:50:71:72:(...):ba:20:e5:4d:4f:bc:01:ce:ba:44

You can also scan for the card reader using pcsc_scan:

❯ pcsc_scan

Then the key and certificate pair can be copied from the p12 archive containing the S/MIME certificate to the key:

❯ pkcs15-init --delete-objects privkey,pubkey --id 3 --store-private-key baptiste_grenier_until_2021_02.p12[0/3084]t pkcs12 --auth-id 3 --verify-pin
Using reader with a card: Nitrokey Nitrokey Pro (0000000000000000000(...)16) 00 00
User PIN required.
Please enter User PIN [Admin PIN]:
Deleted 2 objects
error:23076071:PKCS12 routines:PKCS12_parse:mac verify failure
Please enter passphrase to unlock secret key:
Importing 1 certificates:
  0: /DC=org/DC=terena/DC=tcs/C=NL/O=Stichting EGI/OU=Operations/CN=Baptiste Grenier
❯ pkcs15-init --delete-objects privkey,pubkey --id 2 --store-private-key baptiste_grenier_until_2021_02.p12 --format pkcs12 --auth-id 3 --verify-pin
Using reader with a card: Nitrokey Nitrokey Pro (0000000000000000000(...)16) 00 00
User PIN required.
Please enter User PIN [Admin PIN]:
Deleted 2 objects
error:23076071:PKCS12 routines:PKCS12_parse:mac verify failure
Please enter passphrase to unlock secret key:
Importing 1 certificates:
  0: /DC=org/DC=terena/DC=tcs/C=NL/O=Stichting EGI/OU=Operations/CN=Baptiste Grenier
Failed to store private key: Not supported

According to the Nitrokey documentation the errors can be ignored.

Using neomutt with S/MIME certificate on the Nitrokey Pro 2

Using the Nitrokey Pro 2 with GPG/PGP

Preparing the GPG keys

By security I will not keep the master key on the Nitrokey, but store 3 different secret subkeys each limited to a specific usage, allowing to manage them individually:

  • one for signing
  • one for encrypting
  • one for authenticating

The master secret key should be exported and deleted from local keyring and saved in a secure location (or even multiple secure locations).

Setup on Archlinux

As per Nitrokey documentation libccid is used to interact with the OpenPGP smart card in the Nitrokey.

It doesn’t seem to be available by default in Archlinux, but searching the repositories using trizen I found some nitrokey stuff:

❯ trizen -Ss nitrokey
extra/libnitrokey 3.5-2
    Communicate with Nitrokey stick devices in a clean and easy manner
extra/nitrokey-app 1.4-2
    Nitrokey management application
aur/libnitrokey-git 3.4.1r781.ef171df-1 [unmaintained] [1+] [0.00%] [21 Aug 2018]
    Communicate with Nitrokey stick devices in a clean and easy manner
aur/nitrocli 0.3.1-1 [2+] [0.00%] [4 Jan 2020]
    Command-line interface for Nitrokey devices

So I installed and gave a try at nitokey-app that seems to be an official application by Nitrokey folks, versions for the various OS can be found on their website.

Forward future jump: in fact it’s possible to do everything using gpg.

The first step si to Configure it by Changing the User and Admin PINs. For reference default User PIN is 123456, and Default Admin PIN is 12345678.

It can be done from the Menu of the Nitrokey App.

As said I’m using BitWarden so I will generate and store the PINs in BitWarden, as it’s always handy to be able to check the PIN there before locking the Nitrokey at the 3rd failed unlocking tentative.

Once the PINs have been replaced, the next step is importing the GPG keys in the Nitrokey Pro 2.

# Once plugged the key should show be available to gpg
❯ gpg --card-status
Application type .: OpenPGP
Version ..........: 3.3
Manufacturer .....: ZeitControl
(...)
Name of cardholder: [not set]
Language prefs ...: de
Salutation .......:
URL of public key : [not set]
Login data .......: [not set]
Signature PIN ....: forced
Key attributes ...: rsa2048 rsa2048 rsa2048
Max. PIN lengths .: 64 64 64
PIN retry counter : 3 0 3
Signature counter : 0
KDF setting ......: off
Signature key ....: [none]
Encryption key....: [none]
Authentication key: [none]
General key info..: [none]

Let’s configure the card, you should be asked for the Admin PIN when updating the information:

❯ gpg --card-edit

gpg/card> admin
Admin commands are allowed

gpg/card> name
Cardholder's surname: Baptiste
Cardholder's given name: Grenier

gpg/card> sex
Salutation (M = Mr., F = Ms., or space): M

gpg/card> lang
Language preferences: fr

gpg/card> key-attr
Changing card key attribute for: Signature key
Please select what kind of key you want:
   (1) RSA
   (2) ECC
Your selection? 1
What keysize do you want? (2048) 4096
The card will now be re-configured to generate a key of 4096 bits
Changing card key attribute for: Encryption key
Please select what kind of key you want:
   (1) RSA
   (2) ECC
Your selection? 1
What keysize do you want? (2048) 4096
The card will now be re-configured to generate a key of 4096 bits
Changing card key attribute for: Authentication key
Please select what kind of key you want:
   (1) RSA
   (2) ECC
Your selection? 1
What keysize do you want? (2048) 4096
The card will now be re-configured to generate a key of 4096 bits

gpg/card> list

Reader ...........: 20A0:4108:0000000000000000000(...)16:0
Application ID ...: D2760001240103030005000(...)160000
Application type .: OpenPGP
Version ..........: 3.3
Manufacturer .....: ZeitControl
Serial number ....: 000(...)16
Name of cardholder: Grenier Baptiste
Language prefs ...: fr
Salutation .......: Mr.
URL of public key : https://keys.bapt.name/pubkey.asc
Login data .......: [not set]
Signature PIN ....: forced
Key attributes ...: rsa4096 rsa4096 rsa4096
Max. PIN lengths .: 64 64 64
PIN retry counter : 3 0 3
Signature counter : 0
KDF setting ......: off
Signature key ....: [none]
Encryption key....: [none]
Authentication key: [none]
General key info..: [none]

gpg/card> quit

Let’s now add the three subkeys. As you can see from the following output, I’ve got one master key, that is only used to manage the secret subkeys and that is ideally meant to be kept offilne at a secure place, and 3 secret subkeys that are used for only one purpose: (E)ncrypting, (S)igning and (A)uthenticating.

❯ gpg --edit-key --expert 0xCDA18F02
gpg (GnuPG) 2.2.20; Copyright (C) 2020 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Secret key is available.

sec  rsa4096/XXXXXXXXXXXXXXXX
     created: 2019-04-19  expires: never       usage: SC
     trust: ultimate      validity: ultimate
ssb  rsa4096/XXXXXXXXXXXXXXXX
     created: 2020-07-09  expires: never       usage: E
ssb  rsa4096/XXXXXXXXXXXXXXXX
     created: 2020-07-09  expires: never       usage: S
ssb  rsa4096/XXXXXXXXXXXXXXXX
     created: 2020-07-09  expires: never       usage: A
[ultimate] (1). Baptiste Grenier <baptiste@bapt.name>
[ultimate] (2)  Baptiste Grenier (EGI) <baptiste.grenier@egi.eu>
[ultimate] (3)  Baptiste Grenier <gwarf@gwarf.org>

# Select the first key that will be used for (E)ncryption
gpg> key 1

gpg> keytocard
Please select where to store the key:
   (2) Encryption key
Your selection? 2

# Provide the GPG key passphrase to unlock the gpg secret sub key
# Provide the Nitrokey Administrator PIN code

# Then use the key command to select the key for (S)igning (this command is
# used to toggle selection of a key, beware of not having multiple keys
# selected together) enable the second key
# Deselect key 1
gpg> key 1

# Select key 2
gpg> key 2

gpg> keytocard
Please select where to store the key:
   (1) Signature key
   (3) Authentication key
Your selection? 1

# Finally do the same thing for the authentication key
# used to toggle selection of a key, beware of not having multiple keys
# selected together) enable the second key

# Deselect key 2
gpg> key 2

# Select key 3
gpg> key 3

gpg> keytocard
Please select where to store the key:
   (3) Authentication key
Your selection? 3

# The save
gpg> save

Check the status of the nitrokey in another terminal:

❯ gpg --card-status

Reader ...........: 20A0:4108:0000000000000000000(...)16:0
Application ID ...: D2760001240103030005000(...)160000
Application type .: OpenPGP
Version ..........: 3.3
Manufacturer .....: ZeitControl
Serial number ....: 000(...)16
Name of cardholder: Grenier Baptiste
Language prefs ...: fr
Salutation .......: Mr.
URL of public key : https://keys.bapt.name/pubkey.asc
Login data .......: [not set]
Signature PIN ....: forced
Key attributes ...: rsa4096 rsa4096 rsa4096
Max. PIN lengths .: 64 64 64
PIN retry counter : 3 0 3
Signature counter : 0
KDF setting ......: off
Signature key ....: 3FE2 DB50 7172 1518 (...) 01CE BA44
      created ....: 2020-07-09 16:38:47
Encryption key....: F367 BA47 CDED 90F8 (...) C211 AC0D
      created ....: 2020-07-09 16:37:12
Authentication key: 9E4A 0477 6B6D 3636 (...) 5EF0 57E3
      created ....: 2020-07-09 16:39:14
General key info..: sub  rsa4096/XXXXXXXXXXXXXXXX 2020-07-09 Baptiste Grenier <baptiste@bapt.name>
sec   rsa4096/XXXXXXXXXXXXXXXX  created: 2019-04-19  expires: never
ssb>  rsa4096/XXXXXXXXXXXXXXXX  created: 2020-07-09  expires: never
                                card-no: 0005 000(...)16
ssb>  rsa4096/XXXXXXXXXXXXXXXX  created: 2020-07-09  expires: never
                                card-no: 0005 000(...)16
ssb>  rsa4096/XXXXXXXXXXXXXXXX  created: 2020-07-09  expires: never
                                card-no: 0005 000(...)16

Usage with neomutt

TBD

Usage on MacOS X

Usage on Windows 10

2 Factor authentication with the FIDO U2F

BitWarden

Using 2FA with BitWarden is quite straightforward as it’s documented in the official BitWarden documentation. Basically the Nitrokey FIDO2 key can be registered to your account, and will only have to be connected.

As always it’s always better to always keep mutliple possibilities for doing second factor authentication, like a One Time Password (OTP) generated by an authentification application such as Authy or Google Authenticator.

GitHub

GitHub also provides some official documentation on using a security key for two-factor authentication.

Documnentation