Nitrokey 3: SSH

Previous posts:

The Nitrokey 3 allows at least 2 different ways to improve SSH keys security: with FIDO2 and with PGP.


Since version 8.2, OpenSSH supports FIDO2 for authentication. There are 2 modes, resident keys (the SSH private key will be on the security device) and non-resident (in which case, the unique built-in private key in the security token is combined with a private key handle stored on the computer). In non-resident mode, the key handle will need to be copied on each computer we want to connect from.

Here we don’t have much choice, at the moment only non-resident mode seems to be supported by the Nitrokey 3.

And again we also have a choice of key algorithm, ECDSA-P256 (required by the FIDO2 specifications) and Ed25519 (optional). The first one is generated with the option ecdsa-sk and the second one with ed25519-sk.

Here are the commands to generate keys in resident and non-resident mode for the 2 different algorithms:

ssh-keygen -t ecdsa-sk -O resident -f ~/.ssh/id_ecdsa_sk
ssh-keygen -t ed25519-sk -O resident -f ~/.ssh/id_ed25519_sk
ssh-keygen -t ecdsa-sk -f ~/.ssh/id_ecdsa_sk
ssh-keygen -t ed25519-sk -f ~/.ssh/id_ed25519_sk

As usual, the public key need to be added to the authorized_keys on the remote servers:

$ ssh-copy-id -i ~/.ssh/id_ed25519_sk

Now, to connect to the remote server, the Nitrokey will need to be plugged-in and touched to allow access (during the key generation, the option no-touch-required can be passed to prevent to have to touch the security device).

PGP smart card

Both PGP and SSH use asymmetric cryptography, so with a public and private key pair, and it’s quite tempting to use our PGP key pair for SSH.

First thing is to make sure GPG agent is activated, and it’s configured to support SSH. To do so, add a line with use-agent in file ~/.gnupg/gpg.conf and a line with enable-ssh-support in file ~/.gnupg/gpg-agent.conf. Make sure the agent is restarted to take into account the new configuration by either doing gpg-connect-agent reloadagent /bye or pkill gpg-agent.

Then we need to tell SSH to talk to the GPG agent, and start the GPG agent early on. This can be done by adding the following lines in ~/.bashrc so it will be run when opening a new terminal:

if [ "${gnupg_SSH_AUTH_SOCK_by:-0}" -ne $$ ]; then
  export SSH_AUTH_SOCK="$(gpgconf --list-dirs agent-ssh-socket)"

Check the Nitrokey is taken into account with ssh-add -l, you should get something like that (but with real data):

4096 SHA256:(…) cardno:000000000000 (RSA)

Now we need to export the public key that we will have to import in the remote server’s ~/.ssh/authorized_keys:

$ gpg --export-ssh-key 0123456789ABCDEF >> ~/.ssh/

Now, to connect to the remote server, the Nitrokey will need to be plugged-in and unlocked.

I’d like to require to touch the key each time it’s accessed to use the SSH key. I guess what I’m looking for are the User Interaction Flags, but it requires GnuPG version 2.3, and I have 2.2.

I’ll update this post once I have a newer version of GnuPG.

Next steps:

Comments Add one by sending me an email.