This is a quick cheatsheet for using setting up a Nitrokey 3C as a "security key" to be used with SSH. In this design the private key stays on the device.
Overview
This sets up a new Nitrokey 3C NFC to be used with OpenSSH. OpenSSH now supports FIDO2 and security-keys, avoiding the annoyance of having to deal with GPG / GPG-Agent.
Install the Nitrokey utilities
$ pip install pynitrokey
Perform initial Nitrokey setup.
This initializes the Nitrokey FIDO2 stuff, and sets a PIN
$ nitropy fido2 set-pinCommand line tool to interact with Nitrokey devices 0.13.0Please enter new pin:Please confirm new pin:done - please use new pin to verify key
List credentials
There shouldn't be any, but worth checking!
$ nitropy fido2 list-credentialsCommand line tool to interact with Nitrokey devices 0.13.0Please provide pin:There are no registered credentialsThere is an estimated amount of 13 credential slots left
Generate SSH Key
This is were we actually generate the SSH key.
$ ssh-keygen -t ed25519-sk -O resident -C id_ed25519-sk_nitrokey_2026Generating public/private ed25519-sk key pair.You may need to touch your authenticator to authorize key generation.Enter PIN for authenticator:You may need to touch your authenticator again to authorize key generation.Enter file in which to save the key (/Users/wkumari/.ssh/id_ed25519_sk): /Users/wkumari/.ssh/id_ed25519-sk_nitrokey_2026Enter passphrase for "/Users/wkumari/.ssh/id_ed25519-sk_nitrokey_2026" (empty for no passphrase):Enter same passphrase again:Your identification has been saved in /Users/wkumari/.ssh/id_ed25519-sk_nitrokey_2026Your public key has been saved in /Users/wkumari/.ssh/id_ed25519-sk_nitrokey_2026.pubThe key fingerprint is:SHA256:o4+fO6pDgZOnJ04k/zC5tGHpBag1XZI id_ed25519-sk_nitrokey_2026
We specify:
- ed25519-sk: the keytype to note that this should be stored on a security-key (the FIDO2 Nitrokey).
- resident: the key handle should be stored on the FIDO authenticator itself. This allows us to use the same Nitrokey on multiple devices. While having both parts of the key on the device does slightly increase the risk, an attacker would need to get access to the device, and it is also protected by a (self-wiping) pin.
NOTE: This creates a public key file (id_ed25519-sk_nitrokey_2026.pub) and something that looks like a private key (id_ed25519-sk_nitrokey_2026). This initially startled and confused me, but this is actually just a key-handle.
"FIDO keys consist of two parts: a key handle part stored in the private key file on disk, and a per-device private key that is unique to each FIDO authenticator and that cannot be exported from the authenticator hardware. These are combined by the hardware at authentication time to derive the real key that is used to sign authentication challenges."
If you want to generate a key which can be used without touching the Nitrokey, you can do so by adding the "no-touch-required" option. Note that this also needs to be configured on a per-server basis, see below. I would strongly recommend adding a passphrase to the key (technically key-handle):
$ ssh-keygen -t ed25519-sk -O resident -O no-touch-required -C id_ed25519-sk_nitrokey_2026
Listing new key
Listing keys will now show the new SSH key:
$ nitropy fido2 list-credentialsCommand line tool to interact with Nitrokey devices 0.13.0Please provide pin:There are 1 registered credentials-----------------------------------ssh::- id: a300582dda14807b299ac7e192e4132041c7ddf161eb086a8e08d0250210f1a841e2af00c61f13de40c778738user: openssh-----------------------------------There is an estimated amount of 12 credential slots left
Install SSH Key
We install the public part of the SSH key on devices that we want to SSH to, just like any other SSH public key.
If you want to be able to SSH to the server, prefix the SSH public key with "no-touch-required", for example, in ~/.ssh/authorized_keys:
no-touch-required
If you leave out "no-touch-required" , then you will have to touch the token.
Using the key
To add the key to ssh-agent, you add the identity just like you normally would (including entering the passphrase):
$ ssh-add -DAll identities removed.$ ssh-add -LThe agent has no identities.$ ssh-add ~/.ssh/id_ed25519-sk_nitrokey_2026Enter passphrase for /Users/wkumari/.ssh/id_ed25519-sk_nitrokey_2026:Identity added: /Users/wkumari/.ssh/id_ed25519-sk_nitrokey_2026 (id_ed25519-sk_nitrokey_2026)$ ssh-add -L
As the key is marked "resident" above, you can add it to a new ssh-agent with "ssh-add -K" - this will require entering the token PIN.
I am specifying the identity and not to use my agent in this example because my ssh-agent has other keys for this machine loaded.
$ ssh scratch.example.com -i /Users/wkumari/.ssh/id_ed25519-sk_nitrokey_2026 -o IdentityAgent=none##################################################### Go away! You are not welcome here... ## ## Unauthorized access to this system is forbidden. ## All activity may be monitored and recorded. #####################################################Confirm user presence for key ED25519-SK SHA256:o4+fO6pDgZOnU5BQmqJs6KLgJ04k/zC5tGHpBag1XZIUser presence confirmedWelcome to Ubuntu 24.04.4 LTS (GNU/Linux 6.8.0-137-generic x86_64)...
Done!
