Skip to content

8 PGP SSH Config

Julien Chappuis edited this page Jan 11, 2024 · 4 revisions

Introduction

Table of Contents

The goal is to explain the generation and usage of PGP and SSH keys with Yubikeys.

Reference

DrDuh Yubikey Guide : the procedure below is adapted from DrDuh guide, albeit simplified (and less secure).

Preparation

Install required packages

paru –S openssh gnupg pcsclite ccid hopenpgp-tools yubikey-personalization
Important
hopenpgp-tools installs 100+ Haskell dependencies which are updated super frequently. Uninstall it after this procedure with paru -Rns hopenpgp-tools if you don’t want to be bothered by this.

Configure the services

sudo systemctl enable pcscd.service
sudo systemctl start pcscd.service

A reboot might be required.

Create a temp work environment

export GNUPGHOME=$(mktemp -d -t gnupg_$(date +%Y%m%d%H%M)_XXX)

Now import DrDuh’s GPG config

cd $GNUPGHOME
curl -L "https://raw.githubusercontent.com/drduh/config/master/gpg.conf" -O
grep -ve "^#" $GNUPGHOME/gpg.conf

Generate the keys

We will use the "batch" procedure. For full step by step, check DrDuh Yubikey Guide.

Create the master key

Tip
Generate a strong passphrase for the private key, and get ready to copy/paste it as it will be required many times.
gpgconf --kill gpg-agent
cd $GNUPGHOME
curl -L "https://raw.githubusercontent.com/Jubijub/arch-config/master/home/jubi/.gnupg/gen-params-rsa4096" -O
gpg --batch --generate-key gen-params-rsa4096

Verify the key

gpg --list-key

Export the key ID and the key fingerprint

export KEYID=<copy paste what was after the rsa4096/, usually something like 0x12345467>
export KEYFP=<copy the fingerprint after Key fingerprint = , a bunch of 4 digit groups>

Create the subkeys

gpg --quick-add-key $KEYFP  rsa4096 sign 1y
gpg --quick-add-key $KEYFP rsa4096 encr 1y
gpg --quick-add-key $KEYFP  rsa4096 auth 1y

Add an extra identity (OPTIONNAL)

gpg --expert --edit-key $KEYID


gpg> adduid
Real name: Dr Duh
Email address: DrDuh@other.org
Comment:
You selected this USER-ID:
    "Dr Duh <DrDuh@other.org>"

sec  rsa4096/0xFF3E7D88647EBCDB
    created: 2017-10-09  expires: never       usage: C
    trust: ultimate      validity: ultimate
ssb  rsa4096/0xBECFA3C1AE191D15
    created: 2017-10-09  expires: never       usage: S
ssb  rsa4096/0x5912A795E90DD2CF
    created: 2017-10-09  expires: never       usage: E
ssb  rsa4096/0x3F29127E79649A3D
    created: 2017-10-09  expires: never       usage: A
[ultimate] (1). Dr Duh <doc@duh.to>
[ unknown] (2). Dr Duh <DrDuh@other.org>

gpg> trust
sec  rsa4096/0xFF3E7D88647EBCDB
    created: 2017-10-09  expires: never       usage: C
    trust: ultimate      validity: ultimate
ssb  rsa4096/0xBECFA3C1AE191D15
    created: 2017-10-09  expires: never       usage: S
ssb  rsa4096/0x5912A795E90DD2CF
    created: 2017-10-09  expires: never       usage: E
ssb  rsa4096/0x3F29127E79649A3D
    created: 2017-10-09  expires: never       usage: A
[ultimate] (1). Dr Duh <doc@duh.to>
[ unknown] (2). Dr Duh <DrDuh@other.org>

Please decide how far you trust this user to correctly verify other users\' keys
(by looking at passports, checking fingerprints from different sources, etc.)

  1 = I don't know or won't say
  2 = I do NOT trust
  3 = I trust marginally
  4 = I trust fully
  5 = I trust ultimately
  m = back to the main menu

Your decision? 5
Do you really want to set this key to ultimate trust? (y/N) y

sec  rsa4096/0xFF3E7D88647EBCDB
    created: 2017-10-09  expires: never       usage: C
    trust: ultimate      validity: ultimate
ssb  rsa4096/0xBECFA3C1AE191D15
    created: 2017-10-09  expires: never       usage: S
ssb  rsa4096/0x5912A795E90DD2CF
    created: 2017-10-09  expires: never       usage: E
ssb  rsa4096/0x3F29127E79649A3D
    created: 2017-10-09  expires: never       usage: A
[ultimate] (1). Dr Duh <doc@duh.to>
[ unknown] (2). Dr Duh <DrDuh@other.org>

gpg> uid 1

sec  rsa4096/0xFF3E7D88647EBCDB
created: 2017-10-09  expires: never       usage: C
    trust: ultimate      validity: ultimate
ssb  rsa4096/0xBECFA3C1AE191D15
    created: 2017-10-09  expires: never       usage: S
ssb  rsa4096/0x5912A795E90DD2CF
    created: 2017-10-09  expires: never       usage: E
ssb  rsa4096/0x3F29127E79649A3D
    created: 2017-10-09  expires: never       usage: A
[ultimate] (1)* Dr Duh <doc@duh.to>
[ unknown] (2). Dr Duh <DrDuh@other.org>

gpg> primary

sec  rsa4096/0xFF3E7D88647EBCDB
created: 2017-10-09  expires: never       usage: C
    trust: ultimate      validity: ultimate
ssb  rsa4096/0xBECFA3C1AE191D15
    created: 2017-10-09  expires: never       usage: S
ssb  rsa4096/0x5912A795E90DD2CF
    created: 2017-10-09  expires: never       usage: E
ssb  rsa4096/0x3F29127E79649A3D
    created: 2017-10-09  expires: never       usage: A
[ultimate] (1)* Dr Duh <doc@duh.to>
[ unknown] (2)  Dr Duh <DrDuh@other.org>

gpg> save

Verify the subkeys

gpg -K

It should displey something like this :

gpg -K
/tmp.FLZC0xcM/pubring.kbx
............................................................................
sec   rsa4096/0xFF3E7D88647EBCDB 2017-10-09 [C]
      Key fingerprint = 011C E16B D45B 27A5 5BA8  776D FF3E 7D88 647E BCDB
uid                            Dr Duh <doc@duh.to>
ssb   rsa4096/0xBECFA3C1AE191D15 2017-10-09 [S] [expires: 2018-10-09]
ssb   rsa4096/0x5912A795E90DD2CF 2017-10-09 [E] [expires: 2018-10-09]
ssb   rsa4096/0x3F29127E79649A3D 2017-10-09 [A] [expires: 2018-10-09]
  • Verify the key against GPG best practices

gpg --export $KEYID | hokey lint

Export the key into files

Export the main and sub keys

$ gpg --armor --export-secret-keys $KEYID > $GNUPGHOME/mastersub.key
$ gpg --armor --export-secret-subkeys $KEYID > $GNUPGHOME/sub.key

Create a revocation certificate

$ gpg --output $GNUPGHOME/revoke.asc --gen-revoke $KEYID
  • No specific reason

  • Write a rationale like General purpose revocation certificate and finish with a blank line.

Backup the keys / environment

I choose an insecure approach as I do this for convenience over security, follow DrDuh Yubikey Guide for more secure options.

$ sudo cp -avi $GNUPGHOME ~/Downloads

Export and backup the public key

$ gpg --armor --export $KEYID | sudo tee ~/Downloads/<the name of your temp env>/gpg-$KEYID-$(date +%F).asc
$ gpg --keyserver keys.gnupg.net --send-key $KEYID
$ gpg --keyserver hkps://keyserver.ubuntu.com:443 --send-key $KEYID
$ gpg --keyserver pgp.mit.edu --send-key $KEYID

Configure the Yubikey as a Smartcard

Reset the cards if needed

Warning
This will reset previously installed GPG keys, as well as the pin codes for the key.
Important
You need to do this for all keys you want to use.
ykman openpgp reset

Edit the card

gpg --card-edit

Change the pin / admin pin

gpg/card> admin
Admin commands are allowed

gpg/card> passwd
gpg: OpenPGP card no. D2760001240102010006055532110000 detected

1 - change PIN
2 - unblock PIN
3 - change Admin PIN
4 - set the Reset Code
Q - quit

Your selection? 3
PIN changed.

1 - change PIN
2 - unblock PIN
3 - change Admin PIN
4 - set the Reset Code
Q - quit

Your selection? 1
PIN changed.

1 - change PIN
2 - unblock PIN
3 - change Admin PIN
4 - set the Reset Code
Q - quit

Your selection? q

Edit the other information (name, email, etc.)

gpg/card> name
Cardholder's surname: Duh
Cardholder's given name: Dr

gpg/card> lang
Language preferences: en

gpg/card> login
Login data (account name): doc@duh.to

gpg/card> list

gpg/card> quit

Set retries to 5 attempts

ykman config mode ccid
ykman openpgp access set-retries 5 5 5

Transfer the keys on the Yubikey (repeat for each key)

This process is to be repeated on all keys. Doing so destroy the key, so you will need to restore the environment between keys.

Transfer the keys

$ gpg --edit-key $KEYID

key 1
keytocard
    Select the Sign key (1)
key1

key 2
keytocard
    Select the Encryption key (2)
key2

key 3
keytocard
    Select the Authentication key (3)
key3

save

Verify card

Verify the sub-keys have been moved to YubiKey as indicated by ssb>:

$ gpg -K
/tmp.FLZC0xcM/pubring.kbx
..................................................................................
sec   rsa4096/0xFF3E7D88647EBCDB 2017-10-09 [C]
      Key fingerprint = 011C E16B D45B 27A5 5BA8  776D FF3E 7D88 647E BCDB
uid                            Dr Duh <doc@duh.to>
ssb>  rsa4096/0xBECFA3C1AE191D15 2017-10-09 [S] [expires: 2018-10-09]
ssb>  rsa4096/0x5912A795E90DD2CF 2017-10-09 [E] [expires: 2018-10-09]
ssb>  rsa4096/0x3F29127E79649A3D 2017-10-09 [A] [expires: 2018-10-09]

Restore the temp directory

keytocard is a destructive process, so you will need to restore your backup into $GNUPGHOME

mv -vi $GNUPGHOME $GNUPGHOME.1 (1)
cp -avi ~/Downloads/<the name of your temp env>/ $GNUPGHOME
cd $GNUPGHOME
  1. If you provision more than 2 keys, iterate .1, .2, etc…​

Cleanup (do last after the last key)

$ paru -S srm
$ sudo srm -r $GNUPGHOME || sudo rm -rf $GNUPGHOME
$ gpg --delete-secret-key $KEYID
$ unset GNUPGHOME

Make sure GNUPGHOME is unset, otherwise the commands below won’t work, as it points to a temp directory instead of pointing to ~/.gnupg

At this point your keys are ready to function

GPG setup

Note
If you are reinstalling your computer with existing keys you’d like to reuse, you can directly start at this stage.

Import GPG config

cd ~/.gnupg
curl -L "https://raw.githubusercontent.com/drduh/config/master/gpg.conf" -O
chmod 600 ~/.gnupg/*
chmod 700 ~/.gnupg

Import public key

Import the key

gpg --homedir ~/.gnupg/ --import ~/Downloads/<the name of your temp env>/gpg-public-0x<the key id>-YYYY-MM-DD.asc
export KEYID=<the ID>

Reset the trust to 'Ultimate'

$ gpg --edit-key $KEYID

gpg> trust

Your decision? 5
Do you really want to set this key to ultimate trust? (y/N) y

gpg> quit

Check the card

gpg --card-status

Note : if it doesn’t work, try :

sudo systemctl restart pcscd.service
gpgconf --kill gpg-agent

SSH configuration

Configure gpg-agent

$ cd ~/.gnupg

$ curl -L "https://raw.githubusercontent.com/Jubijub/arch-config/master/home/jubi/.gnupg/gpg-agent.conf" -O

$ grep -ve "^#" gpg-agent.conf
enable-ssh-support
default-cache-ttl 60
max-cache-ttl 120
pinentry-program /usr/bin/pinentry-curses

Configure ZSH / Fish for use with gpg-agent

Zsh

  • Add to .zshrc

export SSH_AUTH_SOCK=$(gpgconf --list-dirs agent-ssh-socket)
gpgconf --launch gpg-agent
  • Add to .zshenv

# Set SSH to use gpg-agent
unset SSH_AGENT_PID
if [ "${gnupg_SSH_AUTH_SOCK_by:-0}" -ne $$ ]; then
  export SSH_AUTH_SOCK="$(gpgconf --list-dirs agent-ssh-socket)"
fi

Fish

# GPG agent
set -x GPG_TTY (tty)
set -x SSH_AUTH_SOCK (gpgconf --list-dirs agent-ssh-socket)
gpgconf --launch gpg-agent

Configure Git, Github, etc.

Configure Git for using signed commits

git config --global user.signingkey $KEYID
git config --global commit.gpgsign true (1)
  1. prevents from having to specify the -S option on git commit to sign the commit. All commits will be autosigned.

Export the keys in a usable format

  • SSH key

ssh-add -L
  • PGP key

gpg --list-secret-keys --keyid-format LONG <email> (1)
gpg --armor --export $KEYID
  1. this line is optional, but you can retrieve the $KEYID if needed

Export the keys in GitHub

  • Go in the interface

  • Add the keys using the exported versions above.

Restoring a working GPG/SSH environment

Use this procedure to restore a working environment

Preparation

  • Download your $GNUPGHOME backup

  • Get hold of your passphrase

  • Insert one of the Yubikeys

Rebuild the GPG / SSH enviornment

Import the latest public key (if the keys are expired, follow the procedure below)

mkdir ~/.gnupg
cd ~/.gnupg
gpg --import /<your backup>/gpg-0x<kEYID>-<date>.asc
export KEYID=<from the output of the previous command>

Import the config files

curl -L "https://raw.githubusercontent.com/drduh/config/master/gpg.conf" -O
curl -L "https://raw.githubusercontent.com/Jubijub/arch-config/master/home/jubi/.gnupg/gpg-agent.conf" -O
chmod 600 ~/.gnupg/*
chmod 700 ~/.gnupg

Restart the daemons

gpg-connect-agent "scd serialno" "learn --force" /bye
gpg-connect-agent updatestartuptty /bye

You may need to close Kitty and reopen it.

Configure Git

git config --global user.signingkey $KEYID
git config --global commit.gpgsign true (1)
  1. prevents from having to specify the -S option on git commit to sign the commit. All commits will be autosigned.

Run checks

gpg -K #(1)
ssh-add -L #(2)
  1. : should show the list of keys, the 2 keys should be prefixed by ssb> meaning they are on the key itself.

  2. : should output the SSH public key, with the card number as the suffix

Modifying / Rotating the keys

Restore the backup environment

export GNUPGHOME=$(mktemp -d -t gnupg_$(date +%Y%m%d%H%M)_XXX)

gpg --import /<your backup>/mastersub.key
cp -v /<your backup>/gpg.conf $GNUPGHOME

Change the expiry date

Edit the main key:

export KEYID=0xFF3E7D88647EBCDB

gpg --expert --edit-key $KEYID

Select all 3 keys and change the date

gpg --edit-key $KEYID

Secret key is available.

sec  rsa4096/0xFF3E7D88647EBCDB
    created: 2017-10-09  expires: never       usage: C
    trust: ultimate      validity: ultimate
ssb  rsa4096/0xBECFA3C1AE191D15
    created: 2017-10-09  expires: 2018-10-09  usage: S
ssb  rsa4096/0x5912A795E90DD2CF
    created: 2017-10-09  expires: 2018-10-09  usage: E
ssb  rsa4096/0x3F29127E79649A3D
    created: 2017-10-09  expires: 2018-10-09  usage: A

gpg> key 1

gpg> key 2

gpg> key 3

gpg> expire
    Set a value of 1y

Export the update public key

This public key will contained updated expiry dates, and that's all that is required.

gpg --armor --export $KEYID > gpg-$KEYID-$(date +%F).asc

Transfer that public key to the computer from which you use your GPG key, and then import it with:

$ gpg --import gpg-0x*.asc

Change the default physical key

gpg-agent will cache the serial number of the Yubikey, which prevents using another Yubikey.

To force gpg-agent to learn the new serial number

gpg-connect-agent "scd serialno" "learn --force" /bye

Troubleshooting

If commit signature, or SSH signature fails

If you get a message like sign_and_send_pubkey: signing failed for RSA "cardno:9 031 456" from agent: agent refused operation :

Close your terminal and restart it. Then launch :

gpg-connect-agent updatestartuptty /bye

If you change your active Yubikey

gpg-agent will cache the serial number of the Yubikey, which prevents using another Yubikey.

To force gpg-agent to learn the new serial number

gpg-connect-agent "scd serialno" "learn --force" /bye
Clone this wiki locally