SSH keys on a YubiKey in a Mac

Last updated October 05, 2019

You may be the sort of person who needs to SSH into remote machines. And you may also be the sort of person who doesn’t like the idea of SSH private keys laying around on your computer(s). If so, here’s how you can generate a PGP key on a YubiKey plugged into a USB port of a Mac, and then use that key with SSH. This way the private key lives its entire life on the YubiKey and is never placed on a disk in your computer.

Disclaimer

The below instructions use Homebrew for installing software purely to simplify the instructions. Determining whether or not using Homebrew to install software on your computer is compatible with your threat model is left as an exercise for you, dear reader. You can certainly acquire the software via other means if you wish.

Software Stuff

  • Install the YubiKey Manager CLI (ykman); alternative installation options can be found here:

      % brew install ykman
    
  • Install GPG >= 2.1. Version 2.1 simplified the running of gpg-agent. The version isn’t a hard requirement, but it might make your life easier.

      % brew install gpg
    
  • (Optional) Install GPGTools’s pinentry-mac GUI for password entry:

      % brew install pinentry-mac
    
  • Add the following lines to ~/.gnupg/gpg-agent.conf (the pinentry-program line is optional):

      enable-ssh-support
      pinentry-program /usr/local/bin/pinentry-mac
    
  • Add the following lines to your ~/.zshrc or whatevs. The second line will start gpg-agent if required.

      export SSH_AUTH_SOCK=$(gpgconf --list-dirs agent-ssh-socket)
      gpg-connect-agent /bye
    
  • If it’s running you should disable ssh-agent

      launchctl stop com.openssh.ssh-agent
      sudo launchctl disable system/com.openssh.ssh-agent
    

YubiKey Stuff

  • Acquire a YubiKey. I like the YubiKey 5 Nano which can live inside a USB-A port on a laptop.

  • Insert the YubiKey into your Mac. You can verify it’s working via:

      % ykman info
      Device type: YubiKey 5 Nano
      Serial number: _________
      Firmware version: _____
      Form factor: Nano (USB-A)
      Enabled USB interfaces: OTP+FIDO+CCID
    
      Applications
      OTP             Enabled
      FIDO U2F        Enabled
      OpenPGP         Enabled
      PIV             Enabled
      OATH            Enabled
      FIDO2           Enabled
      %
    

    At the time of writing (2019-10) Yubico is in the process of rolling out firmware version 5.2.3 to its various YubiKey 5 products. Among other things this new firmware version allows you to generate ECC or RSA keys using the OpenPGP app on the YubiKey. Older versions only support RSA keys. Since you can’t upgrade the firmware on a YubiKey, and they don’t label which version you’re getting on the packaging, you won’t know what you’re getting until you use it. For this example we’ll stick to RSA keys.

  • Change some defaults for the OpenPGP app on the YubiKey. Even though it refers to a “PIN”, alphanumeric and special characters are supported. Here are the default values:

    Default PIN: 123456
    Default Admin PIN: 12345678

      % gpg --card-edit
      gpg/card> admin
      Admin commands are allowed
    
      gpg/card> passwd
      gpg: OpenPGP card no. _________ detected
    
      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? 3
      PIN changed.
    
      1 - change PIN
      2 - unblock PIN
      3 - change Admin PIN
      4 - set the Reset Code
      Q - quit
    
      Your selection? 4
      Reset Code set.
    
      1 - change PIN
      2 - unblock PIN
      3 - change Admin PIN
      4 - set the Reset Code
      Q - quit
    
      Your selection? q
    
      gpg/card> key-attr
      Changing card key attribute for: Signature key
      Please select what kind of key you want:
         (1) RSA
         (2) ECC
      Your selection? 1
      What keysize do you want? (2048) 4096
      The card will now be re-configured to generate a key of 4096 bits
      Changing card key attribute for: Encryption key
      Please select what kind of key you want:
         (1) RSA
         (2) ECC
      Your selection? 1
      What keysize do you want? (2048) 4096
      The card will now be re-configured to generate a key of 4096 bits
      Changing card key attribute for: Authentication key
      Please select what kind of key you want:
         (1) RSA
         (2) ECC
      Your selection? 1
      What keysize do you want? (2048) 4096
      The card will now be re-configured to generate a key of 4096 bits
    
      gpg/card> list
      <...>
      Key attributes ...: rsa4096 rsa4096 rsa4096
      <...>
      Signature key ....: [not set]
      Encryption key....: [not set]
      Authentication key: [not set]
      <...>
    
      gpg/card>
    
  • Generate new keys directly on the YubiKey:

      gpg/card> generate
      Make off-card backup of encryption key? (Y/n) n
    

    Don’t bother backing up the key when prompted; you won’t get the full key anyway and it can’t be used to restore to a new YubiKey. You’ll get a standard set of PGP key creation prompts for your key settings, then your YubiKey’s light (if it has one) will flash for a while while it generates keys. After about 5 minutes you should see:

        public and secret key created and signed.
    
      gpg/card> list
      <...>
      Signature key ....: <key fingerprint>
      Encryption key....: <key fingerprint>
      Authentication key: <key fingerprint>
      <...>
    
      gpg/card> q
      %
    
  • (Optional) Set the YubiKey to require a physical touch before using the keys you just created:

      % ykman openpgp set-touch aut on
      Enter admin PIN:
      Set touch policy of authentication key to on? [y/N]: y
      % ykman openpgp set-touch enc on
      Enter admin PIN:
      Set touch policy of encryption key to on? [y/N]: y
      % ykman openpgp set-touch sig on
      Enter admin PIN:
      Set touch policy of signature key to on? [y/N]: y
      %
    
  • Verify gpg-agent, ssh, and your YubiKey are all playing along nicely. The following should print out your SSH public key; cardno should be the YubiKey’s serial number:

      % ssh-add -L
      ssh-rsa <...> cardno:_________
      %
    
  • Use the above SSH public key in ~/.ssh/authorized_keys on your target machine or however you would normally use it.

  • Verify everything works. SSH to a host, enter your YubiKey’s OpenPGP PIN when prompted, then tap the YubiKey. Try a slightly longer press if it doesn’t work the first time.