Skip to content

Using GPG with Yubikey for SSH Authentication

https://www.esev.com/blog/post/2015-01-pgp-ssh-key-on-yubikey-neo/
https://www.isi.edu/~calvin/yubikeyssh.htm
https://rnorth.org/gpg-and-ssh-with-yubikey-for-mac

Install latest gpgtools (MAC)

brew cask install gpgtools-beta

Backup existing .gnupg directory and create a new one

cd ~
mv .gnupg .gnupg.ori
mkdir .gnupg
cd ~/.gnupg

Create a new gpg.conf file

cat >gpg.conf <<EOF
use-agent
personal-cipher-preferences AES256 AES192 AES CAST5
personal-digest-preferences SHA512 SHA384 SHA256 SHA224
cert-digest-algo SHA512
default-preference-list SHA512 SHA384 SHA256 SHA224 AES256 AES192 AES CAST5 ZLIB BZIP2 ZIP Uncompressed
EOF

Generate PGP keys

Master Key and Subkeys

Your PGP key consists of a master key and one or many subkeys. The master key will be used to CERTIFY (or sign) your subkeys. The subkeys can be configured for one or multiple actions: ENCRYPT, AUTHENTICATE, or SIGN. (A signing subkey means to sign data, as opposed to other keys).

$ gpg --expert --gen-key
gpg (GnuPG/MacGPG2) 2.0.30; Copyright (C) 2015 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.

Please select what kind of key you want:
   (1) RSA and RSA (default)
   (2) DSA and Elgamal
   (3) DSA (sign only)
   (4) RSA (sign only)
   (7) DSA (set your own capabilities)
   (8) RSA (set your own capabilities)
Your selection? 8

Possible actions for a RSA key: Sign Certify Encrypt Authenticate
Current allowed actions: Sign Certify Encrypt

   (S) Toggle the sign capability
   (E) Toggle the encrypt capability
   (A) Toggle the authenticate capability
   (Q) Finished

Your selection? s

Possible actions for a RSA key: Sign Certify Encrypt Authenticate
Current allowed actions: Certify Encrypt

   (S) Toggle the sign capability
   (E) Toggle the encrypt capability
   (A) Toggle the authenticate capability
   (Q) Finished

Your selection? e

Possible actions for a RSA key: Sign Certify Encrypt Authenticate
Current allowed actions: Certify

   (S) Toggle the sign capability
   (E) Toggle the encrypt capability
   (A) Toggle the authenticate capability
   (Q) Finished

Your selection? q
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (2048)
Requested keysize is 2048 bits
Please specify how long the key should be valid.
         0 = key does not expire
      <n>  = key expires in n days
      <n>w = key expires in n weeks
      <n>m = key expires in n months
      <n>y = key expires in n years
Key is valid for? (0) 2y
Key expires at Thu Sep  5 22:13:22 2019 PDT
Is this correct? (y/N) y

GnuPG needs to construct a user ID to identify your key.

Real name: Jeeva Kailasam
Email address: jkailasam@netflix.com
Comment:
You selected this USER-ID:
    "Jeeva Kailasam <jkailasam@netflix.com>"

Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? o
You need a Passphrase to protect your secret key.

We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
gpg: key 2D4279A7 marked as ultimately trusted
public and secret key created and signed.

gpg: checking the trustdb
gpg: 3 marginal(s) needed, 1 complete(s) needed, PGP trust model
gpg: depth: 0  valid:   1  signed:   0  trust: 0-, 0q, 0n, 0m, 0f, 1u
gpg: next trustdb check due at 2019-09-06
pub   2048R/2D4279A7 2017-09-06 [expires: 2019-09-06]
      Key fingerprint = 90E1 809C 3036 2921 1C30  0BC9 7978 2126 2D42 79A7
uid       [ultimate] Jeeva Kailasam <jkailasam@netflix.com>

Verify the key

$ gpg --list-keys
/Users/jkailasam/.gnupg/pubring.gpg
-----------------------------------
pub   2048R/2D4279A7 2017-09-06 [expires: 2019-09-06]
uid       [ultimate] Jeeva Kailasam <jkailasam@netflix.com>

Create a text backup of master key

 gpg -a --export-secret-keys 2D4279A7 > masterkeys.txt

Generate the revocation Certificate for the master key

$ gpg --gen-revoke 2D4279A7 > 2D4279A7.revoke-cert.asc

sec  2048R/2D4279A7 2017-09-06 Jeeva Kailasam <jkailasam@netflix.com>

Create a revocation certificate for this key? (y/N) y
Please select the reason for the revocation:
  0 = No reason specified
  1 = Key has been compromised
  2 = Key is superseded
  3 = Key is no longer used
  Q = Cancel
(Probably you want to select 1 here)
Your decision? 3
Enter an optional description; end it with an empty line:
>
Reason for revocation: Key is no longer used
(No description given)
Is this okay? (y/N) y

You need a passphrase to unlock the secret key for
user: "Jeeva Kailasam <jkailasam@netflix.com>"
2048-bit RSA key, ID 2D4279A7, created 2017-09-06

ASCII armored output forced.
Revocation certificate created.

Please move it to a medium which you can hide away; if Mallory gets
access to this certificate he can use it to make your key unusable.
It is smart to print this certificate and store it away, just in case
your media become unreadable.  But have some caution:  The print system of
your machine might store the data and make it available to others!

Generate Authenticate Subkey

Note: NEO limits the subkey size to 2048 bits or less. It is recommended to use 2048bit sub key.

$ gpg --expert --edit-key 2D4279A7
gpg (GnuPG/MacGPG2) 2.0.30; Copyright (C) 2015 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 key is available.

pub  2048R/2D4279A7  created: 2017-09-06  expires: 2019-09-06  usage: C
                     trust: ultimate      validity: ultimate
[ultimate] (1). Jeeva Kailasam <jkailasam@netflix.com>

gpg> addkey
Key is protected.

You need a passphrase to unlock the secret key for
user: "Jeeva Kailasam <jkailasam@netflix.com>"
2048-bit RSA key, ID 2D4279A7, created 2017-09-06

Please select what kind of key you want:
   (3) DSA (sign only)
   (4) RSA (sign only)
   (5) Elgamal (encrypt only)
   (6) RSA (encrypt only)
   (7) DSA (set your own capabilities)
   (8) RSA (set your own capabilities)
Your selection? 8

Possible actions for a RSA key: Sign Encrypt Authenticate
Current allowed actions: Sign Encrypt

   (S) Toggle the sign capability
   (E) Toggle the encrypt capability
   (A) Toggle the authenticate capability
   (Q) Finished

Your selection? s

Possible actions for a RSA key: Sign Encrypt Authenticate
Current allowed actions: Encrypt

   (S) Toggle the sign capability
   (E) Toggle the encrypt capability
   (A) Toggle the authenticate capability
   (Q) Finished

Your selection? e

Possible actions for a RSA key: Sign Encrypt Authenticate
Current allowed actions:

   (S) Toggle the sign capability
   (E) Toggle the encrypt capability
   (A) Toggle the authenticate capability
   (Q) Finished

Your selection? a

Possible actions for a RSA key: Sign Encrypt Authenticate
Current allowed actions: Authenticate

   (S) Toggle the sign capability
   (E) Toggle the encrypt capability
   (A) Toggle the authenticate capability
   (Q) Finished

Your selection? q
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (2048)
Requested keysize is 2048 bits
Please specify how long the key should be valid.
         0 = key does not expire
      <n>  = key expires in n days
      <n>w = key expires in n weeks
      <n>m = key expires in n months
      <n>y = key expires in n years
Key is valid for? (0) 2y
Key expires at Thu Sep  5 22:28:22 2019 PDT
Is this correct? (y/N) y
Really create? (y/N) y
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.

pub  2048R/2D4279A7  created: 2017-09-06  expires: 2019-09-06  usage: C
                     trust: ultimate      validity: ultimate
sub  2048R/82166A94  created: 2017-09-06  expires: 2019-09-06  usage: A
[ultimate] (1). Jeeva Kailasam <jkailasam@netflix.com>

gpg> save

export secret subkey for backup

gpg -a --export-secret-subkeys 2D4279A7 > subkeys.txt

Configure Yubi Key

Make sure Yubikey is plugged in and if gpg2 can read it:

$ gpg --card-status
Reader ...........: Yubico Yubikey 4 OTP U2F CCID
Application ID ...: D2760001240102010006057641800000
Version ..........: 2.1
Manufacturer .....: Yubico
Serial number ....: 05764180
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]

Change the PIN and Admin PIN from its defaults (123456 and 12345678 respectively)

Admin PIN Lockout: If you incorrectly enter your Admin PIN THREE (3) TIMES, you will be locked out of your YubiKey and it will be useless. You can completely reset your Yubikey if locked out with ResetApplet.

$ gpg --card-edit

gpg/card> admin
Admin commands are allowed

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

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

Your selection? 3
PIN changed.
...
Your selection? 1
PIN changed.
...
Your selection? q

gpg/card> quit

Copy the key to the Yubikey

$ gpg --edit-key 2D4279A7
gpg (GnuPG/MacGPG2) 2.0.30; Copyright (C) 2015 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 key is available.

pub  2048R/2D4279A7  created: 2017-09-06  expires: 2019-09-06  usage: C
                     trust: ultimate      validity: ultimate
sub  2048R/82166A94  created: 2017-09-06  expires: 2019-09-06  usage: A
[ultimate] (1). Jeeva Kailasam <jkailasam@netflix.com>

gpg> toggle

sec  2048R/2D4279A7  created: 2017-09-06  expires: 2019-09-06
ssb  2048R/82166A94  created: 2017-09-06  expires: never
(1)  Jeeva Kailasam <jkailasam@netflix.com>

gpg> key 1

sec  2048R/2D4279A7  created: 2017-09-06  expires: 2019-09-06
ssb* 2048R/82166A94  created: 2017-09-06  expires: never
(1)  Jeeva Kailasam <jkailasam@netflix.com>

gpg> keytocard
Signature key ....: [none]
Encryption key....: [none]
Authentication key: 90F4 9D32 8CAF C26C 3A40  AC46 D26F 240B C525 26BC

Please select where to store the key:
   (3) Authentication key
Your selection? 3

gpg: WARNING: such a key has already been stored on the card!

Replace existing key? (y/N) y

You need a passphrase to unlock the secret key for
user: "Jeeva Kailasam <jkailasam@netflix.com>"
2048-bit RSA key, ID 82166A94, created 2017-09-06


sec  2048R/2D4279A7  created: 2017-09-06  expires: 2019-09-06
ssb* 2048R/82166A94  created: 2017-09-06  expires: never
                     card-no: 0006 05764180
(1)  Jeeva Kailasam <jkailasam@netflix.com>

gpg> save

Verify the key is in the card

$ gpg --card-status
Application ID ...: D2760001240102010006057641800000
Version ..........: 2.1
Manufacturer .....: Yubico
Serial number ....: 05764180
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 ...: 2048R 2048R 2048R
Max. PIN lengths .: 127 127 127
PIN retry counter : 3 0 3
Signature counter : 0
Signature key ....: [none]
Encryption key....: [none]
Authentication key: A5BF C8C8 8555 882E 7675  E3BF 2FAA D173 8216 6A94
      created ....: 2017-09-06 05:27:49
General key info..: sub  2048R/82166A94 2017-09-06 Jeeva Kailasam <jkailasam@netflix.com>
sec   2048R/2D4279A7  created: 2017-09-06  expires: 2019-09-06
ssb>  2048R/82166A94  created: 2017-09-06  expires: 2019-09-06
                      card-no: 0006 05764180

Create SSH Pub Key for the subkey

$ gpgkey2ssh 82166A94 > id_rsa_jkailasam.pub

Note: If gpgkey2ssh command is not found on the system (MAC), install using

$ brew cask install gpgtools

Create gnupg.conf file

cat > ~/.gnupg/gpg-agent.conf <<EOF
pinentry-program /usr/local/MacGPG2/libexec/pinentry-mac.app/Contents/MacOS/pinentry-mac
enable-ssh-support
write-env-file
use-standard-socket
default-cache-ttl 600
max-cache-ttl 7200
debug-level advanced
log-file /tmp/gpg-agent.log
EOF

Append to your ~/.bashrc (or your favorite shell config):

if [ -f "${HOME}/.gpg-agent-info" ]; then
  . "${HOME}/.gpg-agent-info"
  export GPG_AGENT_INFO
  export SSH_AUTH_SOCK
fi
export GPG_TTY=$(tty)

How Copy the subkey to second Yubikey

gpg> keytocard
Signature key ....: [none]
Encryption key....: [none]
Authentication key: [none]

Please select where to store the key:
   (3) Authentication key
Your selection? 3
gpg: secret key already stored on a card


ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDU+8eZt4PdcYbWRPiojMsVHVGxr/bUar93yHe+fQUTpjXvAq56bMQO+bsTC3ZR20MtR1wU74v6Iz9ON6iZdijy4p0rgB7Oj6I7kVzYWy0n+UIyDriLwlcOWinSlvlxZx2CyeJuh1IP/sYgB0jV4JXGiaNH9wZJxpepfC0vLuF9Ip9JwtdOGQtYAAbngtvXPZqnAwAaq4L9AKS6CiA5kRLIkSOW3vx1n7ZmoMpClPU69y2jTWNuueoaBUSaHkgV/5EwDr3cN3KJTfmd0n/b91GengFD4ZyPOlYtXZoCcVAdzesiBHb3QgXDcmwhmb0HoC0ZhbFab/9axFcA5j2yoL+/ COMMENT



$ gpg --delete-secret-keys 82166A94
gpg (GnuPG/MacGPG2) 2.0.30; Copyright (C) 2015 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.


sec  2048R/2D4279A7 2017-09-06 Jeeva Kailasam <jkailasam@netflix.com>

Delete this key from the keyring? (y/N) y
This is a secret key! - really delete? (y/N) y



$ gpg --import subkeys.txt
gpg: key 2D4279A7: secret key imported
gpg: key 2D4279A7: "Jeeva Kailasam <jkailasam@netflix.com>" not changed
gpg: Total number processed: 1
gpg:              unchanged: 1
gpg:       secret keys read: 1
gpg:   secret keys imported: 1



$ gpg --edit-key 2D4279A7
gpg (GnuPG/MacGPG2) 2.0.30; Copyright (C) 2015 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 key is available.

pub  2048R/2D4279A7  created: 2017-09-06  expires: 2019-09-06  usage: C
                     trust: ultimate      validity: ultimate
sub  2048R/82166A94  created: 2017-09-06  expires: 2019-09-06  usage: A
[ultimate] (1). Jeeva Kailasam <jkailasam@netflix.com>

gpg> toggle

sec  2048R/2D4279A7  created: 2017-09-06  expires: 2019-09-06
ssb  2048R/82166A94  created: 2017-09-06  expires: never
(1)  Jeeva Kailasam <jkailasam@netflix.com>

gpg> key 1

sec  2048R/2D4279A7  created: 2017-09-06  expires: 2019-09-06
ssb* 2048R/82166A94  created: 2017-09-06  expires: never
(1)  Jeeva Kailasam <jkailasam@netflix.com>


gpg> keytocard
Signature key ....: [none]
Encryption key....: [none]
Authentication key: [none]

Please select where to store the key:
   (3) Authentication key
Your selection? 3

You need a passphrase to unlock the secret key for
user: "Jeeva Kailasam <jkailasam@netflix.com>"
2048-bit RSA key, ID 82166A94, created 2017-09-06


sec  2048R/2D4279A7  created: 2017-09-06  expires: 2019-09-06
ssb* 2048R/82166A94  created: 2017-09-06  expires: never
                     card-no: 0006 06251774
(1)  Jeeva Kailasam <jkailasam@netflix.com>


gpg> save



$ gpg --card-status
Application ID ...: D2760001240102010006062517740000
Version ..........: 2.1
Manufacturer .....: Yubico
Serial number ....: 06251774
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 ...: 2048R 2048R 2048R
Max. PIN lengths .: 127 127 127
PIN retry counter : 3 0 3
Signature counter : 0
Signature key ....: [none]
Encryption key....: [none]
Authentication key: A5BF C8C8 8555 882E 7675  E3BF 2FAA D173 8216 6A94
      created ....: 2017-09-06 05:27:49
General key info..: sub  2048R/82166A94 2017-09-06 Jeeva Kailasam <jkailasam@netflix.com>
sec#  2048R/2D4279A7  created: 2017-09-06  expires: 2019-09-06
ssb>  2048R/82166A94  created: 2017-09-06  expires: 2019-09-06
                      card-no: 0006 06251774