Skip to content

Instantly share code, notes, and snippets.

@artizirk
Last active April 3, 2024 14:49
Show Gist options
  • Save artizirk/d09ce3570021b0f65469cb450bee5e29 to your computer and use it in GitHub Desktop.
Save artizirk/d09ce3570021b0f65469cb450bee5e29 to your computer and use it in GitHub Desktop.
OpenPGP SSH access with Yubikey and GnuPG

NB: This document describles a 'Old-School' way of using Yubikey with SSH

Modern OpenSSH has native support for FIDO Authentication. Its much simpler and should also be more stable with less moving parts. OpenSSH also now has support for signing arbitary files witch can be used as replacement of gnupg. Git also supports signing commits/tags with ssh keys.

Pros of FIDO

  • Simpler stack / less moving parts
  • Works directly with ssh, ssh-add and ssh-keygen on most computers
  • Simpler
  • Private key can never leave the FIDO device

Cons of FIDO

  • Server needs to support ecdsa-sk or ed25519-sk signatures
  • Can't import your existing SSH keys
  • Private key can never leave the FIDO device for backup purposes.
  • By default ssh-keygen generates a FIDO key that is tied to single computer (key handle is a file in .ssh/)
  • Some FIDO devices do not support resident keys where key handle is saved in the FIDO device itself (makes it harder to use same key on multible computers)
  • My NitroKey Start with Gnuk firmware does not support FIDO :(

Pros of GnuPG

  • Supports older algorithms that are more widely supported on legacy systems like RSA and normal ed25519
  • Can import existing SSH keys
  • Possible to make backups of your keys to multiple OpenPGP cards/yubikeys/print on paper
  • E-mail signing and encryption
  • Fun for hardcore nerds

Cons of GnuPG

  • Very complex
  • Bad UX
  • Hard to understand documentation
  • Breaks easily (wrong ENV variables, pcsc conflicts)
  • Fun for only hardcore nerds...

OpenPGP SSH access with Yubikey and GnuPG

Yubikey, Smart Cards, OpenSC and GnuPG are pain in the ass to get working. Those snippets here sould help alleviate pain.

Notes written here should work on

  • Ubuntu 22.04 with Gnome
  • Debian 12 with Gnome
  • Linux Mint with Cinnamon (needs different environment setup, check comments)
  • Arch Linux with Gnome (pacman instead of apt)

This is not a step by step guide Depending on your environment, some commands might change and some parts can be skipped.

I also recommend reading The Linux Foundation - Protecting code integrity with PGP document. It gives a really good overview of basic GnuPG and OpenPGP consepts

Yubikey Config

To reset and disable not used modes on Yubikey you need the ykman program

You can install it using this command

sudo apt install yubikey-manager

GnuPG usage only needs CCID mode to be enabled. FIDO mode can also be enabled for WebAuthn

# Only enable chip card interface device
ykman config mode FIDO+CCID

# Older ykman (< v4.0) uses different syntax
ykman mode FIDO+CCID

Yubikey OpenPGP applet that is used by GnuPG can be configured with

ykman openpgp

GnuPG environment setup for Ubuntu/Debian and Gnome desktop

Make sure that gnupg, pcscd and scdaemon are installed

sudo apt install gnupg pcscd scdaemon

GnuPG Smart Card stack looks something like this

Yubikey -> pcscd -> scdaemon -> gpg-agent -> gpg commandline tool and other clients

Now we have to tell scdaemon to use pcsc interface instead of the default direct connect mode.

mkdir ~/.gnupg
cat > ~/.gnupg/scdaemon.conf <<'EOF'
disable-ccid
pcsc-driver /usr/lib/x86_64-linux-gnu/libpcsclite.so.1
card-timeout 1

# Always try to use yubikey as the first reader
# even when other smart card readers are connected
# Name of the reader can be found using the pcsc_scan command
# If you have problems with gpg not recognizing the Yubikey
# then make sure that the string here matches exacly pcsc_scan
# command output. Also check journalctl -f for errors.
reader-port Yubico YubiKey
EOF

Under Ubuntu libpcsclite.so is in package called libpcsclite1. dpkg -L libpcsclite1 command can show the location of the lib.

GnuPG Trust Model

Turn on ssh like trust on first use (tofu)

cat > ~/.gnupg/gpg.conf <<'EOF'
trust-model tofu+pgp
EOF

After changing gpg configuration files, it's a good idea to restart gpg-agent.

systemctl --user restart gpg-agent.service

Testing that gpg sees your Yubikey

If everything went well then running following command should show something like this

gpg --card-status 
Reader ...........: Yubico Yubikey 4 CCID 00 00
Application ID ...: D2760001240102010006054860180000
Version ..........: 2.1
Manufacturer .....: Yubico
Serial number ....: 05486018
Name of cardholder: [not set]
Language prefs ...: [not set]
Sex ..............: unspecified
URL of public key : [not set]
Login data .......: [not set]
Signature PIN ....: not forced
Key attributes ...: rsa2048 rsa2048 rsa2048
Max. PIN lengths .: 127 127 127
PIN retry counter : 3 0 3
Signature counter : 0
Signature key ....: [none]
Encryption key....: [none]
Authentication key: [none]
General key info..: [none]

Debugging

Test if Yubikey is detected

pcsc-tools package contains pcsc_scan program that can be used to check that Yubikey is detected.

sudo apt install pcsc-tools

and then run

pcsc_scan

Now you should see Card inserted and removed events on your terminal when connecting and removing Yubikey.

Restart everything

Smart Card middleware

sudo systemctl restart pcscd.service

gpg-agent

systemctl --user restart gpg-agent.service

Check the logs

Run journalctl in another terminal window and look for scdaemon log lines

journalctl -fan100

If you see sharing violation messages then something else is probably trying to use the yubikey via opensc. Check getting-estonian-id-card-and-gnupg-scdaemon-yubikey-work-together

Switch from OpenSSH ssh-agent to GnuPG as ssh-agent

Temporarily

First get you need to get GnuPG agent-ssh-socket path

gpgconf --list-dirs | grep ssh

That should return something like this

agent-ssh-socket:/run/user/1000/gnupg/S.gpg-agent.ssh

And then you can set that path as SSH_AUTH_SOCK environment variable

export SSH_AUTH_SOCK=/run/user/1000/gnupg/S.gpg-agent.ssh

After that ssh-add -l shoud show your Yubikey.

Permanent

This only works with Gnome Display Manager (GDM) under systemd KDE, Cinnamon and other desktops that use different login program might need a different config. Check the comments for more info.

#!/bin/sh

echo "Create required directories"
mkdir ~/.config/autostart
mkdir ~/.config/environment.d

echo "==> Disable Gnome-Keyring ssh component"
cp /etc/xdg/autostart/gnome-keyring-ssh.desktop ~/.config/autostart
echo "Hidden=true" >> ~/.config/autostart/gnome-keyring-ssh.desktop

echo "==> Point ssh agent socket environment variable to GnuPG"
cat > ~/.config/environment.d/99-gpg-agent_ssh.conf <<'EOF'
SSH_AUTH_SOCK=${XDG_RUNTIME_DIR}/gnupg/S.gpg-agent.ssh
EOF

echo "==> Done"
echo
echo "Restart you computer and then GnuPG will be your ssh-agent"
echo

Getting Estonian ID card and GnuPG scdaemon Yubikey work together.

Estonian ID-card uses OpenSC project to access private keys on the smart card. OpenSC also supports Yubikey and that will create conflicts with GnuPG scdaemon.

To fix it you can just disable Yubikey in opensc.

#!/bin/sh

echo "Create required directories"
mkdir ~/.config/environment.d
mkdir ~/.config/opensc

echo "==> Creating user local OpenSC configuration"
cat > ~/.config/environment.d/99-opensc.conf <<'EOF'
OPENSC_CONF=${HOME}/.config/opensc/config
EOF

cat > ~/.config/opensc/config <<'EOF'
app default {
	# debug = 3;
	# debug_file = opensc-debug.txt;

	# Lenovo USB Smartcard Keyboard pinpad implementation is broken
	reader_driver pcsc {
		enable_pinpad = false
    }

	# Only GnuPG uses Yubikey
	ignored_readers = "Yubico YubiKey"

	framework pkcs15 {
		# use_file_caching = true;
	}

	# Force Yubikey to use openpgp applet
	card_atr 3B:F8:13:00:00:81:31:FE:15:59:75:62:69:6B:65:79:34:D4 {
		name = "Yubico Yubikey";
		driver = "openpgp";
	}

}
EOF

echo "==> Done"
echo
echo "Restart your computer and Yubikey support in OpenSC will be disabled"
echo

To make coperation between OpenSC and scdaemon even better then you have to configure scdaemon to use shared access mode, Arch Linux wiki has a short paragraph about that here https://wiki.archlinux.org/index.php/GnuPG#Shared_access_with_pcscd

GnuPG commands

gpg -k or gpg --list-keys - List stored public keys

gpg -K or gpg --list-private-keys - List all stored private keys, # means private key is unavailable, > means private key is on a smartcard

Generate OpenPGP keys with GnuPG

  1. Generate 2048bit RSA master key with Certify(Master) and Sign permissions, expire key after 2 years
gpg --quick-generate-key "Full Name <email@email>" rsa2048 cert,sign 2y
  1. Add a 2048bit RSA encryption subkey that expires after 2 years
gpg --quick-add-key master_key_fingerprint rsa2048 encrypt 2y

where master_key_fingerprint is a 40 char hex string shown when running gpg -K

Converting openssh private key format to pem

man page says that you can use -e option to convert private and public keys to other formats, that seems to be wrong. Instead you can use -p option to request changing the password but not actually setting the password.

cp ~/.ssh/id_rsa /tmp/id_rsa  # Make a copy of the ssh private key
ssh-keygen -p -f /tmp/id_rsa -m pem

Converting pem to OpenPGP

Monkeysphere project includes a pem2openpgp command that can be used to import ssh private keys to gnupg keyring.

sudo apt install libcrypt-openssl-bignum-perl libcrypt-openssl-rsa-perl
curl https://raw.githubusercontent.com/dkg/monkeysphere/master/src/share/keytrans > /tmp/pem2openpgp
chmod +x /tmp/pem2openpgp
/tmp/pem2openpgp 'ssh id_rsa' < /tmp/id_rsa | gpg --import

The imported key is stored without encryption, add it with those commands:

gpg --edit-key <ssh_key_id>

and then use passwd command and type the same password as your master key

passwd

After importing you can use normal gpg --edit-key command to change parameters on this key. GnuPG 2.1 also allows you to move the imported key to be one of your subkeys for authentication. https://security.stackexchange.com/a/160847

Maybe also works

Move imported SSH key to a subkey of another master key

Move the key

  1. Get the imported key keygrip value gpg --with-keygrip -k
  2. gpg --expert --edit-key <master_key_id> where master_key_id is a 40 char hex string shown when running gpg -K
  3. type addkey
  4. select (13) Existing key
  5. Copy and Paste imported ssh key keygrip
  6. Toggle off all capabilities and enable authenticate capability and finish
  7. Set key valid time to 2 years with 2y
  8. Confirm key creation and type your master key password
  9. Type save to save and exit from edit menu

Delete old public ssh key

This key is no longer needed

gpg --expert --delete-keys <ssh_key_id>

where ssh_key_id is a 40 char hex string shown when running gpg -K

Export private keys

Before moving private keys to yubikey you must make a backup of private keys so that when you lose or break your yubikey you could move the same keys to a new yubikey.

gpg --export-secret-keys > secret_keys.asc

Exported keys are encrypted with your master password.

Its also a good idea to print your private keys on a paper because files can bitrot and become unusable after some time.

paperkey < secret_keys.asc > secret_paperkey.txt

https://wiki.archlinux.org/index.php/Paperkey

Move your private keys to Yubikey

gpg --edit-key <master_key_id>

and then use keytocard command to move the primary key to card. Then select first sub key with key 1 and then move that to card with keytocard. Then unselect first key with command key and then select second subkey with key 2 and then do keytocard. After that save and you are done.

Cloning OpenPGP card ID with Gnuk/Nitrokey Start

Edit openpgpcard_aid array in src/openpgp-do.c to contain your target card ID and then compile and flash the resulting firmware.

Alternative option for same key on different OpenPGP cards

You can tell scdaemon to force learn the new card ID with this command gpg-connect-agent "scd serialno" "learn --force" /bye

Source: https://github.com/drduh/YubiKey-Guide#switching-between-two-or-more-yubikeys

Other Notes

scdaemon with shared access for ubuntu 18.04 https://d.arti.ee/scdaemon_2.2.4-1ubuntu1.2_amd64.deb

What do ssb and other mean in gpg --list-keys output

sec => 'SECret key'
ssb => 'Secret SuBkey'
pub => 'PUBlic key'
sub => 'public SUBkey'

# after sec/ssb means that secret key is unavailable, maybe it was exported and then deleted

> after sec/ssb means that secret key is on a smartcard/yubikey

Windows

Copy link

ghost commented Apr 6, 2020

Hi. I'm trying to use Git (SSH) with my Yubikey 5 NFC over Tor. Followed all the instructions on Pop!OS. I'm fairly certain that the issue is NOT tor related. I attempted to test SSH using "ssh -vT git@github.com", got the following output:

OpenSSH_8.0p1 Ubuntu-6build1, OpenSSL 1.1.1c  28 May 2019
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: /etc/ssh/ssh_config line 19: Applying options for *
debug1: /etc/ssh/ssh_config line 55: Applying options for *
debug1: Executing proxy command: exec connect -4 -S localhost:9050 $(tor-resolve github.com localhost:9050) 22
debug1: identity file /home/user2/.ssh/id_rsa type -1
debug1: identity file /home/user2/.ssh/id_rsa-cert type -1
debug1: identity file /home/user2/.ssh/id_dsa type -1
debug1: identity file /home/user2/.ssh/id_dsa-cert type -1
debug1: identity file /home/user2/.ssh/id_ecdsa type -1
debug1: identity file /home/user2/.ssh/id_ecdsa-cert type -1
debug1: identity file /home/user2/.ssh/id_ed25519 type -1
debug1: identity file /home/user2/.ssh/id_ed25519-cert type -1
debug1: identity file /home/user2/.ssh/id_xmss type -1
debug1: identity file /home/user2/.ssh/id_xmss-cert type -1
debug1: Local version string SSH-2.0-OpenSSH_8.0p1 Ubuntu-6build1
debug1: Remote protocol version 2.0, remote software version babeld-72deb3a2
debug1: no match: babeld-72deb3a2
debug1: Authenticating to github.com:22 as 'git'
debug1: SSH2_MSG_KEXINIT sent
debug1: SSH2_MSG_KEXINIT received
debug1: kex: algorithm: curve25519-sha256
debug1: kex: host key algorithm: rsa-sha2-512
debug1: kex: server->client cipher: chacha20-poly1305@openssh.com MAC: <implicit> compression: zlib@openssh.com
debug1: kex: client->server cipher: chacha20-poly1305@openssh.com MAC: <implicit> compression: zlib@openssh.com
debug1: expecting SSH2_MSG_KEX_ECDH_REPLY
debug1: Server host key: ssh-rsa SHA256:nThbg6kXUpJWGl7E1IGOCspRomTxdCARLviKw6E5SY8
debug1: Host 'github.com' is known and matches the RSA host key.
debug1: Found key in /home/user2/.ssh/known_hosts:6
debug1: rekey out after 134217728 blocks
debug1: SSH2_MSG_NEWKEYS sent
debug1: expecting SSH2_MSG_NEWKEYS
debug1: SSH2_MSG_NEWKEYS received
debug1: rekey in after 134217728 blocks
debug1: Will attempt key: cardno:EDIT_So_You_Don't_See_My_Stuff RSA SHA256:EDIT_So_You_Don't_See_My_Stuff agent
debug1: Will attempt key: /home/user2/.ssh/id_rsa 
debug1: Will attempt key: /home/user2/.ssh/id_dsa 
debug1: Will attempt key: /home/user2/.ssh/id_ecdsa 
debug1: Will attempt key: /home/user2/.ssh/id_ed25519 
debug1: Will attempt key: /home/user2/.ssh/id_xmss 
debug1: SSH2_MSG_EXT_INFO received
debug1: kex_input_ext_info: server-sig-algs=<ssh-ed25519,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,ssh-rsa,rsa-sha2-512,rsa-sha2-256,ssh-dss>
debug1: SSH2_MSG_SERVICE_ACCEPT received
debug1: Authentications that can continue: publickey
debug1: Next authentication method: publickey
debug1: Offering public key: cardno:EDIT_So_You_Don't_See_My_Stuff RSA SHA256:EDIT_So_You_Don't_See_My_Stuff agent
debug1: Authentications that can continue: publickey
debug1: Trying private key: /home/user2/.ssh/id_rsa
debug1: Trying private key: /home/user2/.ssh/id_dsa
debug1: Trying private key: /home/user2/.ssh/id_ecdsa
debug1: Trying private key: /home/user2/.ssh/id_ed25519
debug1: Trying private key: /home/user2/.ssh/id_xmss
debug1: No more authentication methods to try.
git@github.com: Permission denied (publickey).

Thanks in advance!

@artizirk
Copy link
Author

artizirk commented Apr 8, 2020

debug1: Next authentication method: publickey
debug1: Offering public key: cardno:EDIT_So_You_Don't_See_My_Stuff RSA SHA256:EDIT_So_You_Don't_See_My_Stuff agent
debug1: Authentications that can continue: publickey

Looks like github does not like your ssh key. Make sure that your Yubikey SSH public key from ssh-add -L command output is added to your github account.

@JohnMcW
Copy link

JohnMcW commented Apr 28, 2020

@LucasZanella GnuPG gpg-agent is setup to emulate a ssh-agent. When I start a new ssh connection then gpg-agent will ask the yubikey to do the authentication with its stored keys.

I'm also asking the same question as @LucasZanella. When I try to SSH, it's just the same behavior - it just asks for my password

@nblyumberg
Copy link

nblyumberg commented Apr 28, 2020

I also have an issue with this using Mint Linux and github. The manual instructions work just fine but for automated way it doesn't seem to work.

nblyumberg@nucleus:~/qmk_firmware$ git fetch
Warning: Permanently added the RSA host key for IP address '140.82.113.3' to the list of known hosts.
git@github.com: Permission denied (publickey).
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.
nblyumberg@nucleus:~/qmk_firmware$ ssh-add -l
The agent has no identities.
nblyumberg@nucleus:~/qmk_firmware$ 

however, once I do the manual steps...

nblyumberg@nucleus:~/qmk_firmware$ ssh-add -l
The agent has no identities.
nblyumberg@nucleus:~/qmk_firmware$ gpgconf --list-dirs | grep ssh
agent-ssh-socket:/run/user/1000/gnupg/S.gpg-agent.ssh
nblyumberg@nucleus:~/qmk_firmware$ export SSH_AUTH_SOCK=/run/user/1000/gnupg/S.gpg-agent.ssh
nblyumberg@nucleus:~/qmk_firmware$ ssh-add -l
2048 SHA256:iHvy....................................eFpU cardno:000xxxxxx (RSA)
nblyumberg@nucleus:~/qmk_firmware$ 

Then I have no problems connecting.

@TomaszBelina
Copy link

I have one issue. When I try to move imported private ssh key to the Yubikey gpg says that:

KEYTOCARD failed: Invalid value

But then the key is generated using pgp it works just fine. Passphrases and key length are exactly the same in both cases

@artizirk
Copy link
Author

artizirk commented May 5, 2020

I have one issue. When I try to move imported private ssh key to the Yubikey gpg says that:

KEYTOCARD failed: Invalid value

But then the key is generated using pgp it works just fine. Passphrases and key length are exactly the same in both cases

It's possible that your imported ssh key is incompatible with Yubikey. For me the ssh key has only worked when generated via ssh-keygen and using RSA 2048 or 4096 bit keys. Other settings do not work.

@artizirk
Copy link
Author

artizirk commented May 5, 2020

I also have an issue with this using Mint Linux and github. The manual instructions work just fine but for automated way it doesn't seem to work.

It's possible that something is still overriding SSH_AUTH_SOCK env variable after you have logged in. The automated way has only been confirmed to work with Ubuntu 18.04 and while using Gnome desktop. One way would be to add the export line end of your .bashrc file, but this will only make ssh work when using it from terminal, GUI tools will not see the new ssh auth socket variable. If I have time I will try to replicate this with a clean Linux Mint install.

@TomaszBelina
Copy link

I have one issue. When I try to move imported private ssh key to the Yubikey gpg says that:

KEYTOCARD failed: Invalid value

But then the key is generated using pgp it works just fine. Passphrases and key length are exactly the same in both cases

It's possible that your imported ssh key is incompatible with Yubikey. For me the ssh key has only worked when generated via ssh-keygen and using RSA 2048 or 4096 bit keys. Other settings do not work.

What do you mean by incompatible ?

@artizirk
Copy link
Author

artizirk commented May 6, 2020

What do you mean by incompatible ?

Main problem is with keys generated using putty.

Can you post here exactly the commands you tried to use to import your into gnupg and then what commands you used to import them to the yubikey?

It would be helpful to also know the output from this command

ssh-keygen -f .ssh/id_rsa.pub -e -m pem | openssl asn1parse -inform PEM

@TomaszBelina
Copy link

Key actually has been generated by putty - doesn't matter any more. Thanks for help.

@artizirk
Copy link
Author

artizirk commented Jul 14, 2020

I also have an issue with this using Mint Linux and github. The manual instructions work just fine but for automated way it doesn't seem to work.

@nblyumberg Linux Mint does not use systemd to setup its ssh-agent and environment variables. Following instructions should work with Linux Mint

  1. Comment out use-ssh-agent in /etc/X11/Xsession.options
  2. Add SSH_AUTH_SOCK=/run/user/1000/gnupg/S.gpg-agent.ssh as a last line to /etc/environment file
  3. Restart your computer
  4. Open terminal and check that SSH_AUTH_SOCK env variable is correct with env | grep ssh
  5. ssh-add -L should show ssh public key from yubikey.

@nblyumberg
Copy link

I also have an issue with this using Mint Linux and github. The manual instructions work just fine but for automated way it doesn't seem to work.

@nblyumberg Linux Mint does not use systemd to setup its ssh-agent and environment variables. Following instructions should work with Linux Mint

  1. Comment out use-ssh-agent in /etc/X11/Xsession.options
  2. Add SSH_AUTH_SOCK=/run/user/1000/gnupg/S.gpg-agent.ssh as a last line to /etc/environment file
  3. Restart your computer
  4. Open terminal and check that SSH_AUTH_SOCK env variable is correct with env | grep ssh
  5. ssh-add -L should show ssh public key from yubikey.

Thanks, this worked perfectly!

@dnavre
Copy link

dnavre commented Sep 20, 2020

What do you mean by incompatible ?

Main problem is with keys generated using putty.

Can you post here exactly the commands you tried to use to import your into gnupg and then what commands you used to import them to the yubikey?

It would be helpful to also know the output from this command

ssh-keygen -f .ssh/id_rsa.pub -e -m pem | openssl asn1parse -inform PEM

Hello, I'm having a similar problem. Would be very grateful if you could help me out. I do not remember if my keys were generated using putty or not as it was more than 10-12 years ago. Here is the output of the command you requested.

➜  .ssh ssh-keygen -f id_rsa.pub.gpg_backup -e -m pem | openssl asn1parse -i -inform PEM
    0:d=0  hl=4 l= 264 cons: SEQUENCE
    4:d=1  hl=4 l= 257 prim:  INTEGER           :D3F670D3DE94E7D52D5F5DCEEB554193DEAC518283DBC3259167B43ACD468D812623266E919DA7F7006CF38C3B0103B2CCFE76213998070BC8A44C9FFA0498017EA2927DE83D98D45F25104038216C1F90F35545CA1C70DB6DBA154370C52578D0987308B63C21822D2AC37CF84ECA358B196D6F69A64DFA49046BEC74C56A9BD22590780EA82A972436A8AED1274481184F4EAC6B4AFB5269AB30147AD958BEAB867E3D924B609054F554A35AE24743AF72C395308BC7B334DFA604D089F9C0BC2AEE6F974FFAC45F97DE735421B2D1055C8CEDCEC91EEFC900E5C807A48A800863224126DBE97A9B6CE3A4BEC7B64960A5A0AA7EB3FE6C8DFD65B5577288D5
  265:d=1  hl=2 l=   1 prim:  INTEGER           :23

The key works absolutely normal with gpg, SSH works and authenticates with remote servers. The problem manifests only when trying to export the key to yubikey via keytocard. Maybe there's some way to "repackage" the key using a newer/friendlier format?

@artizirk
Copy link
Author

The key works absolutely normal with gpg, SSH works and authenticates with remote servers. The problem manifests only when trying to export the key to yubikey via keytocard. Maybe there's some way to "repackage" the key using a newer/friendlier format?

@dnavre Unfortunally your key can not be imported to the Yubikey. You have to generate a new key if you want to use yubikey as a ssh key storage.

Problem is that Yubikey (and other hardware crypto tokens) use fixed function RSA hardware that is quite rigid and only accept RSA keys that have modulus 0x010001 (65537). Software RSA implementations do not have that limitation. Changing of RSA modulus also means that you have to generate a whole new key. Afaik no "repackage" option is available.

From the last line I can see that your key is using modulus 0x23 (35). And that makes sense because putty and apparently old OpenSSH versions used that when generating RSA keys.

If you still really want to use that key on a OpenPGP dongle then I think Gnuk firmware on NitroKey Start can use such keys because Gnuk firmware does RSA calculations in software. I have not tested it my self but I do have some Gnuk compatible dev boards laying around and when I get time I might try to recreate your situation.

@dnavre
Copy link

dnavre commented Sep 22, 2020

The key works absolutely normal with gpg, SSH works and authenticates with remote servers. The problem manifests only when trying to export the key to yubikey via keytocard. Maybe there's some way to "repackage" the key using a newer/friendlier format?

@dnavre Unfortunally your key can not be imported to the Yubikey. You have to generate a new key if you want to use yubikey as a ssh key storage.

Problem is that Yubikey (and other hardware crypto tokens) use fixed function RSA hardware that is quite rigid and only accept RSA keys that have modulus 0x010001 (65537). Software RSA implementations do not have that limitation. Changing of RSA modulus also means that you have to generate a whole new key. Afaik no "repackage" option is available.

From the last line I can see that your key is using modulus 0x23 (35). And that makes sense because putty and apparently old OpenSSH versions used that when generating RSA keys.

If you still really want to use that key on a OpenPGP dongle then I think Gnuk firmware on NitroKey Start can use such keys because Gnuk firmware does RSA calculations in software. I have not tested it my self but I do have some Gnuk compatible dev boards laying around and when I get time I might try to recreate your situation.

@artizirk Thanks a lot for the extensive response. That helped me a lot. I generated a new key and am using that as of now!

@xirkus
Copy link

xirkus commented Oct 18, 2020

Here are some updated instructions I used to get this working with MacOS/OSX: https://gist.github.com/xirkus/20552a9b026413cc84191131bbeeb48a

@TafkaMax
Copy link

Thank you Arti!!!

@Supermagnum
Copy link

Official bug report on the duplicate key issue:
https://bugs.launchpad.net/ubuntu/+source/gnupg/+bug/1950201

@artizirk
Copy link
Author

Yeah, copying keys to card without actually moving them there permanently is tedious and hacky with current gnupg.

One problem that is not mentioned in the bugreport is that even if you manage to create two yubikeys with the same card then you still cant use them both on the same computer as a replacement for eachother. GnuPG will remeber the card id when it moves te key and will only accept the same card/yubikey again in the future. Workaround is to delete your gnupg home folder and import clean public keys that have no info which yubikey has the private keys, in that case gnupg can figure out that it can actually use the other yubikey.

Thats why I have a backup Nitrokey Start dongle that runs Free Software gnuk firmware and allows me to clone a another cards id. This way gnupg accepts my real gnupg card and also the backup without any problems.

@myvesta
Copy link

myvesta commented Mar 16, 2022

apt install commands (from this tutorial) works perfectly on Debian11 too.
I just skipped apt-add-repository ppa:yubico/stable, all packages are already in Debian11 repository.

@dominik-ba
Copy link

ykman mode FIDO+CCID causes

WARNING: The use of this command is deprecated and will be removed!
Replace with: ykman config mode FIDO+CCID

@artizirk
Copy link
Author

@dominik-ba updated the docs, thanks!

@myvesta
Copy link

myvesta commented Mar 25, 2022

@artizirk maybe to put that tutorial is fully valid for Debian11 too?
see my previous comment.

@artizirk
Copy link
Author

@myvesta right, added that and also updated some other parts of the document. Thanks for testing!

@myvesta
Copy link

myvesta commented Mar 25, 2022

Also to mention, maybe GUI for yubikey-pin prompting window is built with Gnome library, but it will actually works with any IDE.
I personally use LXDE, no problem here, whole tutorial is valid.

@kjkent
Copy link

kjkent commented Mar 13, 2023

Just wanted to drop by and say thank you; I've battled GPG/YubiKey issues across different distros for over a year, with the pcscd/gpg exclusive access issues and the like. Previously I was using pcsc-shared in scdaemon.conf; but, this seems to kill PIN caching on OpenSUSE Tumbleweed (though Arch and Fedora seem to be fine). Adding disable-ccid and pcsc-driver /usr/lib64/libpcsclite.so.1 (on Tumbleweed) works flawlessly. I also added card-timeout 1, but I'm unsure of its utility; see https://dev.gnupg.org/T3383

@JazzTp
Copy link

JazzTp commented Aug 13, 2023

Ubuntu 18.04 => Raspberry PI OS 64 bit

HERE'S THE MINIMAL SET OF ACTIONS WHICH SHOULD BE THE ONE HAVING SET UP SSH AUTHENTICATION WITH THE YUBIKEY 5 NFC HERE, USING THE OPENPGP KEYS (I had tried other ways but I should have reverted everything).

  • client Ubuntu 18.04
  • server Raspberry PI OS 64 bit (GitHub has clear instructions on their web site, I haven't tried this with GitHub yet).

ON THE CLIENT (Ubuntu 18.04 here), add the following line to ~/.bashrc

SSH_AUTH_SOCK="`gpgconf --list-dirs | grep ssh | sed 's/agent-ssh-socket://'`" ; export SSH_AUTH_SOCK

Now still on the client, open a new terminal window so it'll have the new environment variable value (I'd recommend to close the previously open terminal windows to avoid any confusion)

Verification, this command
echo $SSH_AUTH_SOCK

here is showing:
/run/user/1000/gnupg/S.gpg-agent.ssh

Now in the new terminal window launch this command and put the result in the clipboard:

ssh-add -L | xclip -selection c

(or just ssh-add -L and then click&drag to select the result and ctrl-shift-c)

ON THE SERVER (here it is a Raspberry PI OS 64 bit):

Paste that, appending it to the content of the file
~/.ssh/authorized_keys/

e.g.
cat >> ~/.ssh/authorized_keys/
ctrl-shift-v
<enter> if necessary to go to a new line, it shouldn't be necessary
ctrl-d
or edit with nano or whatever editor you use.

If the file was not already there and you have created it, you might want to also issue:

chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys

I don't remember if I rebooted the Rasperry PI 4 for it to work, or restarted ssh, or nothing at all, let's say "reboot".

SET UP FINISHED, it has been working for a couple of months here (sshfs too).

Additionally, I'm disabling SSH password authentication on the server:

sudo nano /etc/ssh/ssh_config

change the line
# PasswordAuthentication yes

to

PasswordAuthentication no

@JazzTp
Copy link

JazzTp commented Aug 13, 2023

EDIT: see next post below, push to github Yubikey-ssh-authenticated works from Raspberry PI OS64 up to date, OpenSSH_8.4p1, with the above mentioned line used in ~./bashrc for Ubuntu 18.04:

SSH_AUTH_SOCK="`gpgconf --list-dirs | grep ssh | sed 's/agent-ssh-socket://'`" ; export SSH_AUTH_SOCK

Let me add:

I've just tried using the same key on github, the sensor button blinks, and when I touch it I get an error:

$ git push origin master
ERROR: You're using an RSA key with SHA-1, which is no longer allowed. Please use a newer client or a different key type.
Please see https://github.blog/2021-09-01-improving-git-protocol-security-github/ for more information.

fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.

https://github.blog/2021-09-01-improving-git-protocol-security-github/

If you’re running Git from the command line and using OpenSSH, make sure that you’re using OpenSSH 7.2 or newer, which you can verify with ssh -V

$ ssh -V
OpenSSH_7.6p1 Ubuntu-4ubuntu0.7, OpenSSL 1.0.2n  7 Dec 2017

I have newer than the minimum required of 7.2 on this box.
I'll search if I can generate a new SSH key with the appropriate hash algorithm instead of SHA-1 (OTOH, openpgp keys here are RSA4096, I wouldn't use elliptic curves because I've read they are more vulnerable to post-quantum attacks).

You can get detailed information about GitHub’s supported SSH algorithms and what your client presents by running ssh -vvv git@github.com.

(No time to dig into that right now. Well, their platform their rules, I respect that, although I'd rather only issue a warning that the user's code is not as secure as it could be by using updated tools/algorithms.)

@JazzTp
Copy link

JazzTp commented Aug 17, 2023

HERE'S THE MINIMAL SET OF ACTIONS [...]

The same worked in Raspberry PI OS 64bit... of course AFTER setting up so that the Yubikey works with gpg, in my case not using X11 on the Raspberry PI4 but instead accessing it via SSH console. It's not OFF-TOPIC, being a necessary condition before proceeding to set up for SSH, so here's a list of steps (Yubikey 5 NFC here):

https://support.yubico.com/hc/en-us/articles/360013708900-Using-Your-YubiKey-with-Linux
- copied udev rules from the URL specified in the page
- sudo apt install libu2f-udev scdaemon pinentry-tty
- if folder ~/.gnupg/ is not present: gpg -k should create the folder
- if not previously done, import the public key associated with the private keys stored in the Yubikey
- edit/create file ~/.gnupg/gpg-agent.conf and put this line in it (comment out eventual other pinentry-program lines if any):
pinentry-program /usr/bin/pinentry-tty (I repeat: I'm accessing this Raspberry PI4 via SSH terminal)
- THIS SHOULD NOT BE NECESSARY [EDIT: APPARENTLY IT IS]: add the following line to ~/.bashrc
export GPG_TTY=$(tty)

And after going through the "MINIMAL SET OF ACTIONS" shared above, from this Raspberry PI OS 64 box I can run git push origin master to github and authenticate touching the sensor button on the Yubikey, without any errors.

The pub key generated with ssh-add -L is identical to the one I get on Ubuntu 18.04, and the version of ssh I have on Ubuntu 18.04 is 7.6p1 > 7.2 minimum version number required according to the previously quoted GitHub doc... it's possibly > 7.6p1 what's actually needed.

On Raspberry PI OS 64 I have:

$ ssh -V
OpenSSH_8.4p1 Debian-5+deb11u1, OpenSSL 1.1.1n  15 Mar 2022

@JazzTp
Copy link

JazzTp commented Jan 15, 2024

ON THE CLIENT (Ubuntu 18.04 here), add the following line to ~/.bashrc

SSH_AUTH_SOCK="`gpgconf --list-dirs | grep ssh | sed 's/agent-ssh-socket://'`" ; export SSH_AUTH_SOCK

The same – added into ~/.zshrc instead of .bashrc – worked in Linux Manjaro (installed from manjaro-kde-23.1.2-240102-linux66.iso downloaded 2024-01-14 then updated online).

Of course I had to import the same public key into gpg on Manjaro and also issue gpg --card-status for gpg to start using the authentication key as well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment