Skip to content

Instantly share code, notes, and snippets.

@djsplice
Last active January 12, 2024 00:13
Show Gist options
  • Save djsplice/7650a3e36081255a4805b472669c0eca to your computer and use it in GitHub Desktop.
Save djsplice/7650a3e36081255a4805b472669c0eca to your computer and use it in GitHub Desktop.
Yubikey - PGP - SSH - Git Signing

Instructions largely found from here: https://www.esev.com/blog/post/2015-01-pgp-ssh-key-on-yubikey-neo/ https://www.ahrenstein.com/blog/using-a-yubikey-4-and-gpg-for-ssh-on-a-mac/

Go here if you want to update expiration dates on your keys: https://www.g-loaded.eu/2010/11/01/change-expiration-date-gpg-key/

Best to store master key and backups on an encrypted removable drive. I formatted a USB drive for this purpose.

  1. Mount the encrypted USB drive and link it in to the default .gnupg directory (this will create a new keyring on your encrypted drive) ln -s /Volumes/NONAME .gnupg
  2. Create your new key
gpg --expert --full-generate-key
    Select Option 8 - RSA (set your own capabilities)
    Toggle sign, encrypt, authenticate
    4096 RSA
    Expire 1y
  1. Create revocation cert
    gpg --gen-revoke 17E4368E7B3FFB70B2F124345488D417D56272B8 > /Volumes/NONAME/17E4368E7B3FFB70B2F124345488D417D56272B8-revocation-certificate.asc
  1. Create Encryption subkey
    gpg --edit-key 17E4368E7B3FFB70B2F124345488D417D56272B8
    add key
    option 6
    save
  1. Backup the secret keys
gpg —export-secret-key 17E4368E7B3FFB70B2F124345488D417D56272B8 >  /Volumes/NONAME/17E4368E7B3FFB70B2F124345488D417D56272B8-secret.pgp
  1. Create Signing and Authentication Keys for each yubikey
    gpg --edit-key 17E4368E7B3FFB70B2F124345488D417D56272B8
    addcardkey - encryption key
    addcardkey - authentication key
    save
  1. Transfer Encryption key to card (DON’T SAVE or you will permanently transfer your encryption key to the single Yubikey!)
    gpg --edit-key 17E4368E7B3FFB70B2F124345488D417D56272B8
    toggle
    key 1
    keytocard
    <ctrl-c>
  1. Remove your yubikey - insert next key and repeat the creation of signing and authentication keys
  2. Save and Distribute the public PGP Key (https://pgp.mit.edu/pks/lookup?search=barrows.jeff%40gmail.com&op=index)
  3. Remove the master key - re-enable your local pgp keyring (rm .gnupg; mv .gnupg~ .gnupg)
  4. Update the Yubikey gpg --card-edit
   * admin
   * forcesig #make sure the pin is entered before signing
   * url https://pgp.mit.edu/pks/lookup?search=barrows.jeff%40gmail.com&op=index
   * fetch # Fetech public key into local keyring
   * quit
  1. Verify that the master key is no longer on the keyring (it’s on the USB drive’s keyring!)
    gpg -K
     sec#  rsa4096 2018-01-05 [C] [expires: 2019-01-05]
  1. If you added more than one Signing / Authentication key to support more than one Yubikey, you will have multiple on your local keychain (I setup 3 yubikeys, so I had 3 pairs of ASighing / Authentication keys). This ends up confusing Github commit signing, as it appears to use only the last Signing key on your keychain matching your UID. In my case the last key I had on my keychain was one used for a different Yubikey so I didn’t have the private key available. Turns out, after much head scratching, there is an easy fix. Delete keys from my local keychain that I don’t have private keys for!

  2. With your yubikey inserted you can see which keys you have secrets for by running gpg -K --keyid-format LONG

$ gpg --list-secret-keys --keyid-format LONG
/Users/jeffbarrows/.gnupg/pubring.kbx
-------------------------------------
sec#  rsa4096/5488D417D56272B8 2018-01-05 [C] [expires: 2019-01-05]
      17E4368E7B3FFB70B2F124345488D417D56272B8
uid                 [ultimate] Jeff Barrows <barrows.jeff@gmail.com>
ssb>  rsa2048/DDDEAF66DABF6872 2018-01-05 [E] [expires: 2019-01-05]
ssb#  rsa2048/31A5962AC8FAB5EF 2018-01-05 [S] [expires: 2019-01-05]
ssb#  rsa2048/DE8BD6AD212E4130 2018-01-05 [A] [expires: 2019-01-05]
ssb>  rsa4096/7C31849905FB50B0 2018-01-05 [S] [expires: 2019-01-05]
ssb>  rsa4096/6DF80B9B3DC745F2 2018-01-05 [A] [expires: 2019-01-05]
ssb#  rsa4096/69DD1C74BE38DF62 2018-01-05 [S] [expires: 2019-01-05]
ssb#  rsa4096/441763791984E16A 2018-01-05 [A] [expires: 2019-01-05]
  1. You’ll need to delete all of the subkeys you don’t have secret keys for (EXCEPT FOR THE MASTER ‘Certify' KEY!)
$ gpg --edit-key 17E4368E7B3FFB70B2F124345488D417D56272B8
gpg (GnuPG) 2.2.3; Copyright (C) 2017 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Secret subkeys are available.

pub  rsa4096/5488D417D56272B8
     created: 2018-01-05  expires: 2019-01-05  usage: C
     trust: ultimate      validity: ultimate
ssb  rsa2048/DDDEAF66DABF6872
     created: 2018-01-05  expires: 2019-01-05  usage: E
     card-no: 0006 06108833
sub  rsa2048/31A5962AC8FAB5EF
     created: 2018-01-05  expires: 2019-01-05  usage: S
sub  rsa2048/DE8BD6AD212E4130
     created: 2018-01-05  expires: 2019-01-05  usage: A
ssb  rsa4096/7C31849905FB50B0
     created: 2018-01-05  expires: 2019-01-05  usage: S
     card-no: 0006 06108833
ssb  rsa4096/6DF80B9B3DC745F2
     created: 2018-01-05  expires: 2019-01-05  usage: A
     card-no: 0006 06108833
sub  rsa4096/69DD1C74BE38DF62
     created: 2018-01-05  expires: 2019-01-05  usage: S
sub  rsa4096/441763791984E16A
     created: 2018-01-05  expires: 2019-01-05  usage: A
[ultimate] (1). Jeff Barrows <barrows.jeff@gmail.com>

# Select each key that you want to remove, and run ‘delkey'

gpg> key 441763791984E16A

pub  rsa4096/5488D417D56272B8
     created: 2018-01-05  expires: 2019-01-05  usage: C
     trust: ultimate      validity: ultimate
ssb  rsa2048/DDDEAF66DABF6872
     created: 2018-01-05  expires: 2019-01-05  usage: E
     card-no: 0006 06108833
sub  rsa2048/31A5962AC8FAB5EF
     created: 2018-01-05  expires: 2019-01-05  usage: S
sub  rsa2048/DE8BD6AD212E4130
     created: 2018-01-05  expires: 2019-01-05  usage: A
ssb  rsa4096/7C31849905FB50B0
     created: 2018-01-05  expires: 2019-01-05  usage: S
     card-no: 0006 06108833
ssb  rsa4096/6DF80B9B3DC745F2
     created: 2018-01-05  expires: 2019-01-05  usage: A
     card-no: 0006 06108833
sub  rsa4096/69DD1C74BE38DF62
     created: 2018-01-05  expires: 2019-01-05  usage: S
sub* rsa4096/441763791984E16A
     created: 2018-01-05  expires: 2019-01-05  usage: A
[ultimate] (1). Jeff Barrows <barrows.jeff@gmail.com>

gpg> delkey
Do you really want to delete this key? (y/N) y

# Repeat for all remaining subkeys and ‘save’

gpg> save
  1. You’re now ready to setup SSH Agent config and Github signing

gpg-agent config

$ cat << EOF > ~/.gnupg/gpg-agent.conf
enable-ssh-support
pinentry-program /usr/local/bin/pinentry-mac
default-cache-ttl 60
max-cache-ttl 120
EOF

Update Bash Profile (~/.profile)

#Start GPG Agent if not already started
if [ ! -f "/tmp/gpgStarted.lock" ]; then
    gpg-connect-agent reloadagent /bye
    touch /tmp/gpgStarted.lock
fi

# Enable GPG keys for SSH Auth
if [ -f "${HOME}/.gpg-agent-info" ]; then
     . "${HOME}/.gpg-agent-info"
       export SSH_AUTH_SOCK
fi

Create ~/.gpg-agent-info

SSH_AUTH_SOCK=${HOME}/.gnupg/S.gpg-agent.ssh

Add to .bash_profile

# Start or re-use a gpg-agent.
#
export GPG_TTY="$(tty)"
export SSH_AUTH_SOCK="${HOME}/.gnupg/S.gpg-agent.ssh"
gpg-agent --homedir /Users/jeffbarrows/.gnupg --use-standard-socket --enable-ssh-support --daemon

pgp-agent should be running

 ps -ef | grep gpg
  501  6826     1   0 Sat09AM ??         0:04.59 gpg-agent --homedir /Users/jeffbarrows/.gnupg --enable-ssh-support --daemon

Configure Git to sign

git config --global commit.gpgsign true
git config --global user.signingkey 658B963275E1C8262D1CD3FD7C31849905FB50B0

Upload your public key to your github account

Test your work

  1. Check the Yubikey
$ gpg --card-status

Reader ...........: Yubico Yubikey 4 OTP U2F CCID
Application ID ...: D2760001240102010006061088330000
Version ..........: 2.1
Manufacturer .....: Yubico
Serial number ....: 06108833
Name of cardholder: [not set]
Language prefs ...: [not set]
Sex ..............: unspecified
URL of public key : https://pgp.mit.edu/pks/lookup?op=get&search=0x5488D417D56272B8
Login data .......: [not set]
Signature PIN ....: forced
Key attributes ...: rsa4096 rsa2048 rsa4096
Max. PIN lengths .: 127 127 127
PIN retry counter : 3 0 3
Signature counter : 31
Signature key ....: 658B 9632 75E1 C826 2D1C  D3FD 7C31 8499 05FB 50B0
      created ....: 2018-01-05 04:43:10
Encryption key....: A238 5DBB 4B58 0BC8 8460  F170 DDDE AF66 DABF 6872
      created ....: 2018-01-05 04:18:17
Authentication key: ECAB 7100 6253 9826 9C51  FD4B 6DF8 0B9B 3DC7 45F2
      created ....: 2018-01-05 04:46:31
General key info..: sub  rsa4096/7C31849905FB50B0 2018-01-05 Jeff Barrows <barrows.jeff@gmail.com>
sec#  rsa4096/5488D417D56272B8  created: 2018-01-05  expires: 2019-01-05
ssb>  rsa2048/DDDEAF66DABF6872  created: 2018-01-05  expires: 2019-01-05
                                card-no: 0006 06108833
ssb>  rsa4096/7C31849905FB50B0  created: 2018-01-05  expires: 2019-01-05
                                card-no: 0006 06108833
ssb>  rsa4096/6DF80B9B3DC745F2  created: 2018-01-05  expires: 2019-01-05
                                card-no: 0006 06108833

Test GPG Encryption

 echo "$(uname -a)" | gpg --encrypt --armor --recipient 7C31849905FB50B0
-----BEGIN PGP MESSAGE-----

hQEMA93er2bav2hyAQf/cZGuS56Jd87ohNIcAComLGdQ8i1+VR6UMz0ueuVYx+lO
cmw4AhiebDrwHz+Lwk4ZcL8C4TluU1kU1wcwaAEQEfZgw8YNV5uijyVOwgX41KfK
b0nrLoG3AHOGhIQUA8MagzETGu9DPikV1J10SCLErrQsBdzsWWjJsnvfiUG+51Rn
Ltns+gWwygidmEwRnqwBKZNz2xX0oAWw+TluHbykcCkuTP8Hn4FR2LfVSOrA6DM2
8LxtvKdBv8FFxw1m6oGTXXA1WjUWbTHUOYKEZdxMmcvQ2lbIQ/3f3jCxV6ltBcTm
uuSBCYerls5JD1eJtLrqG0W7LOeqrjAc7c5m//TYMtK0AaLf1VSw7I8hCUJMnMQs
MjkSbG6NIvhCJvgel4FExVACNTnfIw3r0j3tD9uPJ2U7v6R/s6fMvYdhjseTsguv
uokrRbBFcUASQzfVSogOSTmhiPIhGTayIvrz5oieYvnOEWkrVHmKZHgoivE7lD92
ENGaWuLwXqJpxN3KZ/+0Q6WpFaIpq9epYDaAOcV0UwHz5Jm6OJlOsFu44Wde0uQ5
5ncUq7mA9VhXyJM16wic50xa1SnB
=S0yp
-----END PGP MESSAGE-----
jeffbarrows@lowend-iMac ~/Documents/code/node-js/lessons/node-chat-app$$ gpg --decrypt --armor
-----BEGIN PGP MESSAGE-----

hQEMA93er2bav2hyAQf/cZGuS56Jd87ohNIcAComLGdQ8i1+VR6UMz0ueuVYx+lO
cmw4AhiebDrwHz+Lwk4ZcL8C4TluU1kU1wcwaAEQEfZgw8YNV5uijyVOwgX41KfK
b0nrLoG3AHOGhIQUA8MagzETGu9DPikV1J10SCLErrQsBdzsWWjJsnvfiUG+51Rn
Ltns+gWwygidmEwRnqwBKZNz2xX0oAWw+TluHbykcCkuTP8Hn4FR2LfVSOrA6DM2
8LxtvKdBv8FFxw1m6oGTXXA1WjUWbTHUOYKEZdxMmcvQ2lbIQ/3f3jCxV6ltBcTm
uuSBCYerls5JD1eJtLrqG0W7LOeqrjAc7c5m//TYMtK0AaLf1VSw7I8hCUJMnMQs
MjkSbG6NIvhCJvgel4FExVACNTnfIw3r0j3tD9uPJ2U7v6R/s6fMvYdhjseTsguv
uokrRbBFcUASQzfVSogOSTmhiPIhGTayIvrz5oieYvnOEWkrVHmKZHgoivE7lD92
ENGaWuLwXqJpxN3KZ/+0Q6WpFaIpq9epYDaAOcV0UwHz5Jm6OJlOsFu44Wde0uQ5
5ncUq7mA9VhXyJM16wic50xa1SnB
=S0yp
-----END PGP MESSAGE-----gpg: encrypted with 2048-bit RSA key, ID DDDEAF66DABF6872, created 2018-01-05
      "Jeff Barrows <barrows.jeff@gmail.com>"
Darwin lowend-iMac.local 17.3.0 Darwin Kernel Version 17.3.0: Thu Nov  9 18:09:22 PST 2017; root:xnu-4570.31.3~1/RELEASE_X86_64 x86_64
^C
gpg: signal Interrupt caught ... exiting

Test GPG Signing

  1. You should get prompted for your yubikey pin so it can read the key
$ echo "$(uname -a)" | gpg --armor --clearsign --default-key 7C31849905FB50B0
gpg: using "7C31849905FB50B0" as default secret key for signing
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

Darwin lowend-iMac.local 17.3.0 Darwin Kernel Version 17.3.0: Thu Nov  9 18:09:22 PST 2017; root:xnu-4570.31.3~1/RELEASE_X86_64 x86_64
-----BEGIN PGP SIGNATURE-----

iQIzBAEBCAAdFiEEZYuWMnXhyCYtHNP9fDGEmQX7ULAFAlpSY8QACgkQfDGEmQX7
ULBwww/7Bpms+AcxUeY+aS9LBbD89TwffksSbBMhTGb70ZpbYyIp8/tZJE9OOEja
gakpuYGxkCjDcFSPlGNpVB7yYt7JNMDqbYvtNA1Q/mFur648g7H3q8wXhO8WAVLA
JQWVS2+gLipmNbFQEHpAgkVRDUfqkC1VrZrxE61+DvHQSh56hO/NGKTzVzSasWJT
Ytn+RmJ+vIul4IYpHeTQsMihPGzhMdwC4olTMOuxdCwr05QHlCWsXL8ZPtOE7+Al
QxSvZHSSjrAS3CyrhZqvZ4y5BdU1A8lEKeDfpZqvrsvWkVSbxxrHhT8JAXiWvHpD
BNbm7Edaj6fbTU38qKq/JKeJMAI4Y3SgUWn6uca6QvoHat883cyVXZ2nBKxhFiQi
AxwuCdJBTbRh/nhQIO5szfWT3GXuRD0eVepX26u5tZcWckV5jqIftGKBgwhrSlGF
wBqJ3a9HsUm5lACaeQEAqldns2KQcr269KRannale2XP62zphsUyEZ4vXdqE1v4o
MlMK3etU7bJ/XyHU3cVNYudroLjYidS3lBi3nLjxw3RWOrnxPtPwnrEv+rzux/UU
okZ7bvvDqLX2vllMTUh5XpHS+ja8SVw98JbctIKOCwr/3YfKwYsPVzmnEXwQtN+O
HgNKgzyJxwZVNQj691+VoUIgO6UQgis3IkB1BKLXwpL4+E8HMvQ=
=IbuQ
-----END PGP SIGNATURE-----
jeffbarrows@lowend-iMac ~/Documents/code/node-js/lessons/node-chat-app$$ gpg
gpg: WARNING: no command supplied.  Trying to guess what you mean ...
gpg: Go ahead and type your message ...
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

Darwin lowend-iMac.local 17.3.0 Darwin Kernel Version 17.3.0: Thu Nov  9 18:09:22 PST 2017; root:xnu-4570.31.3~1/RELEASE_X86_64 x86_64
-----BEGIN PGP SIGNATURE-----

iQIzBAEBCAAdFiEEZYuWMnXhyCYtHNP9fDGEmQX7UDarwin lowend-iMac.local 17.3.0 Darwin Kernel Version 17.3.0: Thu Nov  9 18:09:22 PST 2017; root:xnu-4570.31.3~1/RELEASE_X86_64 x86_64
LAFAlpSY8QACgkQfDGEmQX7
ULBwww/7Bpms+AcxUeY+aS9LBbD89TwffksSbBMhTGb70ZpbYyIp8/tZJE9OOEja
gakpuYGxkCjDcFSPlGNpVB7yYt7JNMDqbYvtNA1Q/mFur648g7H3q8wXhO8WAVLA
JQWVS2+gLipmNbFQEHpAgkVRDUfqkC1VrZrxE61+DvHQSh56hO/NGKTzVzSasWJT
Ytn+RmJ+vIul4IYpHeTQsMihPGzhMdwC4olTMOuxdCwr05QHlCWsXL8ZPtOE7+Al
QxSvZHSSjrAS3CyrhZqvZ4y5BdU1A8lEKeDfpZqvrsvWkVSbxxrHhT8JAXiWvHpD
BNbm7Edaj6fbTU38qKq/JKeJMAI4Y3SgUWn6uca6QvoHat883cyVXZ2nBKxhFiQi
AxwuCdJBTbRh/nhQIO5szfWT3GXuRD0eVepX26u5tZcWckV5jqIftGKBgwhrSlGF
wBqJ3a9HsUm5lACaeQEAqldns2KQcr269KRannale2XP62zphsUyEZ4vXdqE1v4o
MlMK3etU7bJ/XyHU3cVNYudroLjYidS3lBi3nLjxw3RWOrnxPtPwnrEv+rzux/UU
okZ7bvvDqLX2vllMTUh5XpHS+ja8SVw98JbctIKOCwr/3YfKwYsPVzmnEXwQtN+O
HgNKgzyJxwZVNQj691+VoUIgO6UQgis3IkB1BKLXwpL4+E8HMvQ=
=IbuQ
-----END PGP SIGNATURE-----
gpg: Signature made Sun Jan  7 10:15:32 2018 PST
gpg:                using RSA key 658B963275E1C8262D1CD3FD7C31849905FB50B0
gpg: Good signature from "Jeff Barrows <barrows.jeff@gmail.com>" [ultimate]

Test Git commit

  • When you git commit -am"Foo" you should get prompted for your Yubikey PIN
  • Looking at your commit history in github should show 'verified'
  • $ git log --show-signature
commit 9686ff87cc398689b08c3084e180d8cdb75888aa (HEAD -> master)
gpg: Signature made Sun Jan  7 10:18:06 2018 PST
gpg:                using RSA key 658B963275E1C8262D1CD3FD7C31849905FB50B0
gpg:                issuer "barrows.jeff@gmail.com"
gpg: Good signature from "Jeff Barrows <barrows.jeff@gmail.com>" [ultimate]
Author: Jeff Barrows <barrows.jeff@gmail.com>
Date:   Sun Jan 7 10:18:06 2018 -0800

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