How to setup Nitrokey on FreeBSD

I've promised my past self to write this howto for my future self to avoid frustration of getting Nitrokey working on FreeBSD.

Step 1: Install stuff​


Code:
pkg install gnupg pinentry-efl pcsc-lite u2f-devd libccid

At the moment of writing this, I'm using Enlightenment desktop environment, that's why I'm installing efl flavoured pinentry.
You can find alternatives that better fit your needs with pkg search

Code:
pkg search pinentry
# pinentry-1.3.3                 Collection of simple PIN or passphrase entry dialogs
# pinentry-curses-1.3.3          Curses version of the GnuPG password dialog
# pinentry-efl-1.3.3             EFL version of the GnuPG password dialog
# pinentry-fltk-1.3.3            FLTK version of the GnuPG password dialog
# pinentry-gnome-1.3.3           GNOME version of the GnuPG password dialog
# pinentry-gtk2-1.3.3            GTK 2.0 version of the GnuPG password dialog
# pinentry-qt5-1.3.3             Qt 5 version of the GnuPG password dialog
# pinentry-qt6-1.3.3             Qt 6 version of the GnuPG password dialog
# pinentry-tty-1.3.3             Console version of the GnuPG password dialog

Step 2: configure and enable and start pcsc​


Code:
sysrc pcscd_flags=--disable-polkit
sysrc pcscd_enable="YES"

This will update /etc/rc.conf, but you already know that.

Code:
service pscsd start

Step 3: Add users to u2f group​


Code:
pw groupmod u2f -m graudeejs

Step 4: Configure gpg as/for user​


Disable ccid in scdaemon

~/.gnupg/scdaemon.conf
Code:
disable-ccid

If case you don't have ~/.gpupg directory, just execute gpg. I'll create it with proper permissions

step 5: Set point GPG agent to pinentry app and enable SSH support​


~/.gpupg/gpg-agent.conf
Code:
pinentry-program /usr/local/bin/pinentry-efl
enable-ssh-support

Naturally specify pinentry that you prefer.

Step 6: Use your gpg card​


Code:
gpg --card-status
# Reader ...........: Nitrokey Nitrokey 3 [CCID/ICCD Interface] 00 00
# Application ID ...: D276000124010304000F586595D90000
# Application type .: OpenPGP
# Version ..........: 3.4
# Manufacturer .....: Nitrokey
# Serial number ....: 12345768
# Name of cardholder: Aldis Berjoza
# Language prefs ...: en
# Salutation .......: Mr.
# URL of public key : https://redacted.example.com/keys/v3.asc
# Login data .......: graudeejs
# Signature PIN ....: forced
# Key attributes ...: ed25519 cv25519 ed25519
# Max. PIN lengths .: 127 127 127
# PIN retry counter : 3 3 3
# Signature counter : 351
# KDF setting ......: off
# UIF setting ......: Sign=on Decrypt=off Auth=off
# Signature key ....: 2BDD 19C3 9A56 6942 3703  9A87 F1BB EF0C C2C0 6754
#       created ....: 2023-08-01 19:53:43
# Encryption key....: A94D 0E0C 6468 9DD7 E7D4  C0A8 4805 B465 25AA 22DA
#       created ....: 2023-08-01 19:54:26
# Authentication key: 03FD DEA1 6A91 DB58 BCF0  5446 7FD1 4316 DF90 887E
#       created ....: 2023-08-01 19:55:27
# General key info..: sub  ed25519/F1BBEF0CC2C06754 2023-08-01 Aldis Berjoza <redacted@example.com>
# sec#  ed25519/D5112D740F5544E7  created: 2023-08-01  expires: 2030-01-17
# ssb>  ed25519/F1BBEF0CC2C06754  created: 2023-08-01  expires: 2027-01-18
#                                 card-no: 000F 586595D9
# ssb>  cv25519/4805B46525AA22DA  created: 2023-08-01  expires: 2027-01-18
#                                 card-no: 000F 586595D9
# ssb>  ed25519/7FD14316DF90887E  created: 2023-08-01  expires: 2027-01-18
#                                 card-no: 000F 586595D9

If you see something like message above, then all is good.

If it doesn't work try killing scdaemon before retrying:
Code:
killall -KILL scdaemon


Step 7: Import your GPG public key​


If you have your public GPG key stored somewhere on the net and your Nitorkey has configured URL of key you can simply run:
Code:
gpg --card-edit

and type `fetch` in gpg/card prompt.

gpg will fetch and import your public key. Finally type `quit`

At this point you should set key owner trust.

Code:
gpg --edit-key aldis
Code:
gpg> trust
5

Naturally I trust my key Ultimately (5).

Step 8: configure SSH agent​


You need to whilelist your key for SSH usage via gpg-agent. For this you need to obtain keygrip of your key

Code:
gpg --list-keys --with-keygrip
# pub   ed25519 2023-08-01 [C] [expires: 2030-01-17]
#       075BA1E783175EA818C534F3D5112D740F5544E7
#       Keygrip = B3A158D440DC6DFBF1E8C1AD6F741164702C72E6
# uid           [ultimate] Aldis Berjoza <redacted@example.com>
# sub   ed25519 2023-08-01 [S] [expires: 2027-01-18]
#       2BDD19C39A56694237039A87F1BBEF0CC2C06754
#       Keygrip = BE08C2B39A1381DD23AE70A5750B9B064FCF9503
# sub   cv25519 2023-08-01 [E] [expires: 2027-01-18]
#       A94D0E0C64689DD7E7D4C0A84805B46525AA22DA
#       Keygrip = 77787AC2EF7E600814A7CB5B6A76D1B554F42E74
# sub   ed25519 2023-08-01 [A] [expires: 2027-01-18]
#       03FDDEA16A91DB58BCF054467FD14316DF90887E
#       Keygrip = 1BC18F9FF4F6F81BED82EF0A91E70DF1AEA03DF3

I have multiple subkeys. You are looking for Keygrip of certification key (`[C]`). In my case, keygrip is `B3A158D440DC6DFBF1E8C1AD6F741164702C72E6`

You need to add this keygrip to ~/.gnupg/sshcontrol
Code:
B3A158D440DC6DFBF1E8C1AD6F741164702C72E6

It's also possible to explicitly disable key in sshcontrol by prefixing it with `!`.

In some time in the future this step may change:

Step 9: Configure your environment​


Since we're going to use Nitrokey for SSH authentication, we will not use ssh-agent. Instead we will use gpg-agent.
We need to configure `SSH_AUTH_SOCK` environment variable.

There are multiple places where this can be done, I generally work in GUI environment, so one option is to set it in ~/.xinitrc, which is how I currently start my desktop environment (with startx)

Whatever the case something like this needs to be set:
Code:
export SSH_AUTH_SOCK=$(gpgconf --list-dirs agent-ssh-socket)

Step 10: Log out​


Log out and log in, to ensure that `u2f` group as well as `SSH_AUTH_SOCK` is properly set. In fact verify that

Step 11: Test​


Assuming you have GitLab account simply run:
Code:
ssh -T git@gitlab.com
# Welcome to GitLab, @graudeejs!

If it works you will be asked for smartcard pin (via pinentry). Once you enter correct code ssh will login and you will be greeted by GitLab.

Sometimes I've noticed that SSH will not trigger pinentry, a simple workaround is to decrypt some encrypted file.
Code:
gpg --decrypt previously_encrypted_file.gpg

Random notes​


  • Depending on your Nitrokey firmware version it may be necessary to update it. Some old firmware versions would not work on FreeBSD, but if you received new Nitrokey recently than firmware is already recent enough.
  • Sometimes you need to decrypt something to unlock GPG key before you can SSH into server. Don't know why but sometimes SSHing into server doesn't trigger GPG key/pinentry.
 
Back
Top