Richard North’s Blog

[Deprecated] GPG and SSH with Yubikey for Mac

Important! This blog post is now out of date and should­n’t be re­lied upon. I’m leav­ing it in place for his­to­ry’s sake.

The Yubikey Neo [affiliate] is a great, in­ex­pen­sive se­cu­rity de­vice that sup­ports Universal 2nd Factor au­then­ti­ca­tion to web ser­vices and OpenPGP smart card sup­port.

Yubikey Neo

Yubikey Neo

The goal of this post is to de­scribe the setup steps for:

The lat­ter es­tab­lishes a sec­ond fac­tor for con­trol­ling ac­cess that can­not be com­pro­mised sim­ply by theft of an SSH pri­vate key and/​or use of a key­log­ger. With the pri­vate key for GPG and SSH held on the Yubikey, it is much more se­cure than if it were held on the lo­cal hard disk.

This post is writ­ten to help set this up for Macs run­ning Yosemite or El Capitan, us­ing Fish shell. It is as­sumed that Homebrew and brew cask are in­stalled.

This post is a com­bi­na­tion/​dis­til­la­tion of a hand­ful of HOWTO guides I found use­ful for get­ting this set up. This was com­piled a lit­tle af­ter I ac­tu­ally per­formed the process, so if there are any er­rors/​omis­sions please let me know.

Preparing the Yubikey #

Install Yubikey man­age­ment tools:

$ brew update
$ brew cask update
$ brew cask install yubikey-neo-manager yubikey-personalization-gui
$ brew install yubikey-personalization

Insert the Yubikey into your USB port.

Set the Yubikey’s mode to al­low con­cur­rent OpenPGP SmartCard and OTP us­age:

$ ykpersonalize -m82

Install GPG Tools for Mac:

$ brew cask install gpgtools

Set up PINs for GPG on the Yubikey. If at this stage you re­ceive a card er­ror’, try re­mov­ing and rein­sert­ing the Yubikey.

Note: if you en­ter the fac­tory de­fault PIN in­cor­rectly too many times the Yubikey will be­come blocked. It seems that it may be pos­si­ble to re­set this, but I have not tested this.

First, set an ad­min PIN (factory de­fault is 12345678). Next, set your user PIN (factory de­fault is 123456).

$ gpg --card-edit
... snip ...
gpg/card> admin
Admin commands are allowed

gpg/card> passwd

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

Creating a pub­lic/​pri­vate key pair #

Next, cre­ate a key on the de­vice. We’ll choose not to make an off-card backup of the key, and to have the key ex­pire af­ter 1 year:

$ gpg --card-edit
gpg/card> admin
gpg/card> generate
Make off-card backup of encryption key? (Y/n) n
gpg: 3 Admin PIN attempts remaining before card is permanently locked
Admin PIN
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) 1y
Is this correct? (y/N) y

You need a user ID to identify your key; the software constructs the user ID
from the Real Name, Comment and Email Address in this form:
"Heinrich Heine (Der Dichter) <[email protected]>"

Real name: ...
Email address: ...
Comment: tester
You selected this USER-ID:

Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O
gpg: generating new key
gpg: please wait while key is being generated ...
gpg: key generation completed (45 seconds)
gpg: signatures created so far: 0
gpg: signatures created so far: 0
You need a Passphrase to protect your secret key.

gpg: signatures created so far: 2
gpg: signatures created so far: 2
gpg: generating new key
gpg: please wait while key is being generated ...
gpg: key generation completed (25 seconds)
gpg: signatures created so far: 4
gpg: signatures created so far: 4
gpg: key 79C56617 marked as ultimately trusted
public and secret key created and signed.
gpg: checking the trustdb
gpg: 3 marginal(s) needed, 1 complete(s) needed, classic trust model
gpg: depth: 0  valid:   1  signed:   0  trust: 0-, 0q, 0n, 0m, 0f, 1u
pub   2048R/79C56617 2015-08-25
Key fingerprint = ...
uid                  ...
sub   2048R/... ...
sub   2048R/... ...

I’ve re­moved spe­cific el­e­ments from the above, but note the pub­lic key ID you re­ceive (in my case, this was 79C56617).

Next, ex­port the GPG pub­lic key some­where safe for later use:

$ gpg --armor --export <your public key ID> > ~/

Open up the GPG Keychain’ ap­pli­ca­tion and right click on your key­pair (it should show with sec/​pub, in bold).

Firstly, gen­er­ate a Revoke Certificate and store it in a safe place. You will need to use this to re­voke your key if you lose your Yubikey.

Next, do Send pub­lic key to Keyserver’.

Configuring GPG Agent #

This step al­lows GPG Agent to au­then­ti­cate your SSH ses­sions. Edit ~/.gnupg/gpg-agent.conf:

pinentry-program /usr/local/MacGPG2/libexec/
default-cache-ttl 600
max-cache-ttl 7200
debug-level advanced
log-file /var/log/gpg-agent.log

Note that:

Next, as I’m us­ing fish shell, I had to add this to my shell con­fig­u­ra­tion to start GPG Agent with my shell. Put the fol­low­ing in ~/.config/fish/

# Start or re-use a gpg-agent.
gpgconf --launch gpg-agent

# Ensure that GPG Agent is used as the SSH agent
set -U -x SSH_AUTH_SOCK ~/.gnupg/S.gpg-agent.ssh

(Added 2016-04-17): With the re­lease of GPG Agent Autostart in v2.1 of GPG, this sec­tion has be­come vastly eas­ier! Changes are re­flected above.

Now, restart your shell to make GPG Agent re­load.

Using GPG for SSH lo­gin #

With GPG Agent run­ning, not much more needs to be done to use the Yubikey for SSH au­then­ti­ca­tion. We still need to ob­tain your pub­lic key in a for­mat that SSH can un­der­stand:

$ gpgkey2ssh <your public key ID> > ~/

This yields a reg­u­lar SSH for­mat pub­lic key. Next, edit the com­ment sec­tion (final part of the file).

You can now trans­fer this SSH pub­lic key in the usual man­ner to:

If you’ve suc­cess­fully set up your Yubikey, GPG Agent and pro­vided your new pub­lic key to Github, the fol­low­ing should tell you your Github user­name (mine is rnorth, as seen here):

$ ssh [email protected]
PTY allocation request failed on channel 0
Hi rnorth! You've successfully authenticated, but GitHub does not provide shell access.
Connection to closed.

Testing GPG for en­cryp­tion and sign­ing #

To check that your base GPG setup works, try the fol­low­ing:

$ gpg --sign -a

Type Hello World! fol­lowed by new­line and Ctrl-D. The out­put should look vaguely sim­i­lar to:

Comment: GPGTools -


References #

The fol­low­ing ex­cel­lent guides were used in de­riv­ing these steps:

← Home