Nitrokey 3

goals:

  • Initial device setup
  • OpenPGP card setup
  • PIV setup
  • FIDO setup
  • KeepassXC integration

udev rules

udev is a device manager for the Linux kernel that dynamically manages and creates device nodes in the /dev directory.

udev rules
# fetch rules
$ curl -OL https://raw.githubusercontent.com/Nitrokey/nitrokey-udev-rules/main/41-nitrokey.rules

# move rules to udev rules
> mv 41-nitrokey.rules /etc/udev/rules.d/

# change permissions
> chown root:root /etc/udev/rules.d/41-nitrokey.rules
> chmod 644 /etc/udev/rules.d/41-nitrokey.rules

# reload rules and trigger event manually
> udevadm control --reload-rules \
  && udevadm trigger

nitropy setup

nitropy is a command-line interface for the Nitrokey FIDO2, Nitrokey Start, Nitrokey 3, Nitrokey Passkey and NetHSM

Nitropy
# install python pipx
> pacman -S python-pipx

# install nitropy
$ pipx ensurepath \
  && pipx install pynitrokey
# will be stored in "$HOME/.local/bin/nitropy"

# example command are:
$ nitropy nk3 'list|update|factory-reset'

update and reset

after updating the device a reset was neccessary on my side to get it finally running

~/.gnupg/scdaemon.conf
# update device
$ nitropy nk3 factory-reset

# reset after update
$ nitropy nk3 factory-reset

gpg setup

official documentation:

~/.gnupg/scdaemon.conf
# disables the built-in CCID driver of GnuPG's scdaemon
disable-ccid
~/.gnupg/gpg-agent.conf
# cache passphrase for 300 seconds
default-cache-ttl 300
# maximum time how long the passphrase can be cached at all
max-cache-ttl 7200
read card
# check card status
$ gpg2 -vvv --card-status
  ...
  gpg: enabled compatibility flags:
  gpg: selecting card failed: No such device
  gpg: OpenPGP card not available: No such device

# kill agent if the cmd prints error
$ pkill gpg-agent

# try it again
$ gpg2 -vvv --card-status
  ...
  Reader ...........: Nitrokey Nitrokey 3 [CCID/ICCD Interface] 00 00
  Application ID ...: XXXXXXXXXXXXXXXXXXXXXXXX
  Application type .: OpenPGP
  Version ..........: 3.4
  Manufacturer .....: Nitrokey

set pins

official documentation:

gpg
# set/change fido pin
$ nitropy fido2 set-pin
$ nitropy fido2 change-pin

# set/change secrets pin
$ nitropy nk3 secrets set-pin
$ nitropy nk3 secrets change-pin

# set openpgp card user pin (default is: 123456)
$ gpg --card-edit
  passwd

# set openpgp card admin pin (default is: 12345678)
$ gpg --card-edit
  admin
  passwd
  3

# change piv (default is: 123456), requires pkg: 'pivy'
$ pivy-tool change-pin

# change puk (default is: 123456), requires pkg: 'pivy'
$ pivy-tool change-puk

set algorithms

supported algorithms
RSA-2048
RSA-3072 (no key generation, key import only)
RSA-4096 (no key generation, key import only)
EcDSA and ECDH for P256
EdDSA and ECDH for Curve25519

setup Edward 25519

curve25519
# check current algorithm
$ gpg --card-status | grep Key\ attributes
  ...
  Key attributes ...: rsa2048 rsa2048 rsa2048

# open card
$ gpg2 --card-edit
  gpg/card> admin
  ...
  Admin commands are allowed

  # change attributes
  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? 2
  Please select which elliptic curve you want:
     (1) Curve 25519 *default*
     (4) NIST P-384
     (6) Brainpool P-256
  Your selection? 1
  The card will now be re-configured to generate a key of type: ed25519
  Note: There is no guarantee that the card supports the requested
        key type or size.  If the key generation does not succeed,
        please check the documentation of your card to see which
        key types and sizes are supported.
  Changing card key attribute for: Encryption key
  Please select what kind of key you want:
     (1) RSA
     (2) ECC
  Your selection? 2
  Please select which elliptic curve you want:
     (1) Curve 25519 *default*
     (4) NIST P-384
     (6) Brainpool P-256
  Your selection? 1
  The card will now be re-configured to generate a key of type: cv25519
  Changing card key attribute for: Authentication key
  Please select what kind of key you want:
     (1) RSA
     (2) ECC
  Your selection? 2
  Please select which elliptic curve you want:
     (1) Curve 25519 *default*
     (4) NIST P-384
     (6) Brainpool P-256
  Your selection? 1
  The card will now be re-configured to generate a key of type: ed25519

# leave card and check status again
> gpg --card-status | grep Key\ attributes
  ...
  Key attributes ...: ed25519 cv25519 ed25519

create keys

Generate GPG keys on device:

keys creation
# open card editor
> gpg2 --card-edit

  # change to admin
  gpg/card> admin
  ...
  Admin commands are allowed

  # create keys
  gpg/card> generate

  # no off-card backups
  Make off-card backup of encryption key? (Y/n) n

  # key dont expire
  Key is valid for? (0)

  # add details
  Real name: Jane Doe
  Email address: jane@example.com
  Comment: jdoe
  You selected this USER-ID:
  "Jane Doe (jdoe) <jane@example.com>"

  # confirm data
  Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O

  # expected output
  public and secret key created and signed.

add aliases

To add more email addresses we use the adduid function while the device is plugged-in.

keys creation
# list all private keys and pick your target key_id
> gpg --list-secret-keys --keyid-format=long

# edit the target key
> gpg --edit-key XXXXXXXXXXXX

  # add aliases
  gpg> adduid

  # add name, email address and comments
  Real name: Jane Doe
  Email address: jane2@example.com
  Comment: jdoe2
  You selected this USER-ID:
  "Jane Doe (jdoe2) <jane2@example.com>"

  # confirm data
  Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O

  # system will ask for device pin

  # save key
  gpg> save

piv setup

installing pivy
# install pivy-tool to "/opt/pivy/bin/"
$ git clone https://github.com/arekinath/pivy
$ cd pivy; make
> make install

piv reset

reset piv
# reset PIV smartcard if nothing works like on my side
# the rest of the device will stay untouched
$ opensc-tool \
  -s 00:A4:04:00:0B:A000000308000010000100 \
  -s 00:20:00:80:08:FFFFFFFFFFFFFFFF \
  -s 00:20:00:80:08:FFFFFFFFFFFFFFFF \
  -s 00:20:00:80:08:FFFFFFFFFFFFFFFF \
  -s 00:FB:00:00

# setup after reset
$ pivy-tool setup

# get smartcard info
$ pivy-tool list

piv ssh

piv ssh
# fetch public key from PIV smartcard
$ pivy-tool -a eccp256 generate 9A
$ pkcs15-tool --read-ssh-key 1

# connect to server using pkcs#11
$ ssh example.org -I /usr/lib64/opensc-pkcs11.so

# use pivy-agent to benefit from ssh-agent
# pivy-agent -g <your_guid> <your_shell>
> pivy-agent -g XXXXXXXXXXX zsh

# enter piv pin to unlock agent
> ssh-add -X

# check ssh-agent in sub-shell
> ssh-add -l

see: https://github.com/arekinath/pivy

fido2

FIDO2 is a modern, two-factor authentication standard that enables passwordless login, providing a higher level of security through public key cryptography by authenticating users with hardware devices or biometric verification

fido ssh

# create a resident key, saved on the token instead
$ ssh-keygen -t ed25519-sk \
  -O resident \
  -O verify-required \
  -C "FIDO Token"

# list key on device
> nitropy fido2 list-credentials

# on server side, you could add to "/etc/ssh/sshd_config"
PubkeyAuthOptions verify-required

fido luks setup

# install fido library
> pacman -S libfido2

# refresh initramfs
> mkinitcpio -P

# list devices
$ systemd-cryptenroll --fido2-device=list

# list keyslots
> systemd-cryptenroll /dev/nvme0n1p2

# enroll fido on encrypted device
> systemd-cryptenroll \
  --fido2-device=auto \
  --fido2-with-client-pin=true \
  --fido2-with-user-presence=true \
  --fido2-credential-algorithm=eddsa \
  /dev/nvme0n1p2

# modify systemd-boot config
# - rd.luks.options=fido2-device=auto
> edit /boot/loader/entries/arch.conf
  ...
  options rd.luks.options=fido2-device=auto ...

# update bootloader
> bootctl update

# add hooks to initramfs
# - systemd
# - sd-vconsole
# - sd-encrypt
> edit /etc/mkinitcpio.conf
  ...
  # before
  HOOKS=(base udev autodetect modconf block keyboard keymap encrypt lvm2 filesystems fsck shutdown)
  # after
  HOOKS=(base udev systemd autodetect modconf block keyboard sd-vconsole keymap encrypt lvm2 sd-encrypt filesystems fsck shutdown)

# refresh initramfs
> mkinitcpio -P

# reboot and test

see arch wiki

keepassxc

# create a 20 bytes length key
$ dd if=/dev/urandom of=/tmp/nk3 bs=20 count=1

# add key to device' slot 1 or 2
$ nitropy nk3 secrets add-challenge-response 1 $(base32 /tmp/nk3)

# repeat adding the key to all backup devices as well

# remove key locally
$ shred /tmp/nk3
$ rm /tmp/nk3

create a database backup first


  1. In KeepassXC go to: Database > Database Security

  2. Click on: add Challange-Response

  3. Test all devices before clicking on OK.

  4. Ensure that a password is set if you need one, same for an eventual keyfile

  5. Click OK

alternative way

See this linux-bibel.at post as well if you like hold it more handy.

# generate a passphrase and encrypt it using nk3
$ keepassxc-cli generate --length 64 -l -U -n | \
  gpg --encrypt --recipient <your_keyID> --output ~/keepassxc-pw_encrypted.gpg

# use the passphrase to create a KeepassXC database
$ printf "`gpg --quiet --decrypt ~/keepassxc-pw_encrypted.gpg`\n`gpg --quiet --decrypt ~/keepassxc-pw_encrypted.gpg`" | \
  keepassxc-cli db-create -p ~/keepassxc-datenbank.kdbx 2> /dev/null

# run KeepassXC while reading the decrypted secret from stdin
$ gpg --decrypt ~/keepassxc-pw_encrypted.gpg | \
  keepassxc ~/keepassxc-datenbank.kdbx --pw-stdin

general handling

# removing gpg keys locally after unplugging device
$ gpg --delete-secret-and-public-key XXXXXX

# extract ssh key
$ gpg2 --export-ssh-key XXXXXX > ~/.ssh/id_nk3.pub

# remove challange-response from device
$ nitropy nk3 secrets list
$ nitropy nk3 secrets remove HmacSlot1

# remove fido from luks
> systemd-cryptenroll \
  --wipe-slot=fido2 \
  /dev/nvme0n1p2

Great blog about: https://dokuwiki.nausch.org/doku.php/nitrokey:linuxmint:3cnfc