Yubikey, Smart Cards, OpenSC and GnuPG are pain in the ass to get working. Those snippets here sould help alleviate pain.
To reset and disable not used modes on Yubikey you need the ykman
program
You can install it using those commands
sudo apt-add-repository ppa:yubico/stable
sudo apt update
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 mode FIDO+CCID
Yubikey OpenPGP applet that is used by GnuPG can be configured with
ykman openpgp
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
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.
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
Make sure that gnupg, pcscd and scdaemon are installed
sudo dnf install gnupg opensc ccid pcsc-lite pcsc-tools pcsc-lite-libs
sudo systemctl start pcscd.service
sudo systemctl enable pcscd.service
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/lib64/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
reader-port Yubico YubiKey
EOF
Under Fedora libpcsclite.so is in package called pcsc-lite-libs.
dnf provides /usr/lib64/libpcsclite.so.1
orrpm -ql pcsc-lite-libs
command can show the location of the lib.
Turn on ssh like trust on first use (tofu)
cat > ~/.gnupg/gpg.conf <<'EOF'
trust-model tofu+pgp
EOF
debug1: Authentications that can continue: publickey
debug1: Next authentication method: publickey
debug1: Offering public key: cardno:000123456789 RSA SHA256:abcdefghijklmnopqrstuvwzyz123 agent
debug1: Server accepts key: cardno:000123456789 RSA SHA256:abcdefghijklmnopqrstuvwzyz123 agent
sign_and_send_pubkey: signing failed: agent refused operation
debug1: No more authentication methods to try.
git@github.com: Permission denied (publickey).
If you get the issue above, just try: gpg-connect-agent updatestartuptty /bye
~
❯ gpg --card-status
gpg: selecting card failed: No such device
gpg: OpenPGP card not available: No such device
If you get the issue above, just try systemctl restart pcscd
. If this fixes the issue, try adding ExecStartPre=/bin/sleep 30
to /lib/systemd/system/pcscd.service
.
If you get...
debug1: Next authentication method: publickey
debug1: Trying private key: /home/snuggle/.ssh/id_rsa
debug1: Trying private key: /home/snuggle/.ssh/id_dsa
debug1: Trying private key: /home/snuggle/.ssh/id_ecdsa
debug1: Trying private key: /home/snuggle/.ssh/id_ed25519
debug1: Trying private key: /home/snuggle/.ssh/id_xmss
debug1: No more authentication methods to try.
instead of...
debug1: Next authentication method: publickey
debug1: Offering public key: cardno:000123456789 RSA SHA256:abcdefghijklmnopqrstuvwzyz123 agent
debug1: Server accepts key: cardno:000123456789 RSA SHA256:abcdefghijklmnopqrstuvwzyz123 agent
debug1: Trying private key: /home/snuggle/.ssh/id_rsa
debug1: Trying private key: /home/snuggle/.ssh/id_dsa
debug1: Trying private key: /home/snuggle/.ssh/id_ecdsa
debug1: Trying private key: /home/snuggle/.ssh/id_ed25519
debug1: Trying private key: /home/snuggle/.ssh/id_xmss
debug1: No more authentication methods to try.
then it is likely that your shell's echo $SSH_AUTH_SOCK
variable is incorrect. It usually should look something like this:
~
❯ echo $SSH_AUTH_SOCK
/run/user/1000/gnupg/S.gpg-agent.ssh
To fix this, you can try adding the following:
bash: echo "export SSH_AUTH_SOCK=${XDG_RUNTIME_DIR}/gnupg/S.gpg-agent.ssh" >> ~/.bashrc
fish: echo "set -g SSH_AUTH_SOCK {$XDG_RUNTIME_DIR}/gnupg/S.gpg-agent.ssh" >> ~/.config/fish/config.fish
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]
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.
Smart Card middleware
sudo systemctl restart pcscd.service
gpg-agent
systemctl --user restart gpg-agent.service
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
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.
#!/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 "Logout and after login GnuPG will be your ssh-agent"
echo
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 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 "Logout and after login Yubikey support in OpenSC will be disabled"
echo
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 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
- 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
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
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
- Get the imported key keygrip value
gpg --with-keygrip -k
gpg --expert --edit-key <master_key_id>
wheremaster_key_id
is a 40 char hex string shown when runninggpg -K
- type
addkey
- select
(13) Existing key
- Copy and Paste imported ssh key keygrip
- Toggle off all capabilities and enable authenticate capability and finish
- Set key valid time to 2 years with
2y
- Confirm key creation and type your master key password
- Type
save
to save and exit from edit menu
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
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
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.
scdaemon with shared access for ubuntu 18.04 https://d.arti.ee/scdaemon_2.2.4-1ubuntu1.2_amd64.deb
- https://gist.github.com/artizirk/71d7ae140c58f38e45d84d34f7fcc341
- https://github.com/lfit/itpol/blob/master/protecting-code-integrity.md
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