This is a very short guide to getting smartcards working for SSH key authentication. It is focused on minimal intervention - that is to say I tried to work with the tools the operating system provides rather than ask you to install extra software.
Since I use a YubiKey for both home and work that's the example device (YubiKey 5 Series or FIPS Series both work the same for this purpose), but any PKCS11 card that supports an Authentication key will work, the only difference is getting the certificate/public key out so you can convert it.
My assumption is you are performing most of this work on either a Linux system, a BSD system, or a Mac - Basically somewhere you have access to openssh, openssl, and a YubiKey Manager program.
Use the YubiKey Manager to generate a certificate in Slot 9a (Authentication)
If you're working in an environment that has PKI do this right and generate a CSR, have that signed with all the right extensions and key usage constraints, and import the certificate back to your YubiKey.
If you're just using this on your own as a better/more securely portable solution than keys in files on a USB thumb drive then the certificate & expiration date don't matter. Just let the YubiKey tool generate a self-signed certificate.
NOTE: YOU MUST USE SLOT 9a
Previously other slots would work, but either the PKCS11 drivers (providers) have gotten pickier about this or OpenSSH is being more specific about what kind of key it wants.
Export the certificate from the YubiKey using the YubiKey Manager.
The GUI version has a handy Export button, if you're using a command
line version it's something like ykman piv export 9a YubiKey-9a.crt
The export gives you a PEM-format public certificate. Useful, but not here.
To make it into something SSH can understand use OpenSSL to extract the
public key:
openssl x509 -pubkey -in YubiKey-9a.crt -noout > YubiKey-9a.pub
That gives you just the public key, but it's in PKCS8 format so OpenSSH
still won't like it. Take that .pub file and run it through ssh-keygen:
ssh-keygen -f YubiKey-9a.pub -i -mPKCS8
The output of that command is suitable for adding to your authorized_keys file. Tack a comment on the end so you remember what YubiKey serial number it's on or some other useful identifier so you can remove it if you lose the key (or know which line to change if you accidentally nuke the private key on your token).
To use your YubiKey the client device needs to know how to talk to it and get keys. That means you need a PKCS11 provider (driver, library, whatever) that OpenSSH can talk to to request keys.
OS X 10.13.2 (High Sierra) & later makes the client stuff pretty seamless.
Just add
PKCS11Provider /usr/lib/ssh-keychain.dylib
to your ~/.ssh/config
file and OpenSSH will try to get keys from whatever
smartcard or PKCS11 device is currently plugged in.
This will prompt you for your SmartCard PIN when you SSH somewhere, and then you just tap your blinking YubiKey.
If you want to save yourself the password you can use ssh-agent.
Just plug in your smartcard and run the following command:
ssh-add -s /usr/lib/ssh-keychain.dylib
When it adds the keys the agent keeps track of which keys are on cards & retains the PIN, so all you need to do is tap the blinking YubiKey. You only need to run ssh-add when you reboot, log out, or kill the agent, it should take care of everything else (including you adding or removing your smartcard) internally.
Any recent version of Linux or any one of the BSDs should have an OpenSSH new enough that things work just like they did on the Mac, but you will. probably need to install a PKCS11 provider.
The usual one to use is OpenSC. It's in FreeBSD ports as "security/opensc" and in Debian packages as "opensc" - I'm sure you'll find it for other distributions too but if not compile it yourself from https://github.com/OpenSC/OpenSC/releases
Find where your particular system installs opensc-pkcs11.so (it's usually
/usr/lib/opensc-pkcs11.so
or /usr/local/lib/opensc-pkcs11.so
) and use
that file in place of /usr/lib/ssh-keychain.dylib from the Mac instructions.
As of Windows 10 you can easily install OpenSSH on Windows. (Settings UI under Apps -> Apps & Features, select "Manage optional features", hit "Add a feature" and look for "OpenSSH Client (Beta)" in the list). Unfortunately as of February 2019 it's still a shit old version that doesn't support PKCS11.
All is not lost though - Microsoft has a better OpenSSH available!
Just grab the latest one from GitHub at:
https://github.com/PowerShell/Win32-OpenSSH/releases
Extract the zip file and either add that directory to the front of your PATH variable or make sure you're in the spot where it got extracted when you run ssh. There's an install script in the release zip file but it looks somewhat half-assed. Use at your own discretion until Microsoft updates the version you can get in the Optional Features section.
You will also need a PKCS11 provider because Windows doesn't come with
one. I recommend OpenSC (they have MSI packages, though they aren't
signed so you get the "Unknown Developer" warning).
Grab their latest 64-bit release from GitHub at:
https://github.com/OpenSC/OpenSC/releases
When you install the MSI the OpenSC PKCS11 driver gets installed at
C:\Program Files\OpenSC Project\OpenSC\pkcs11\opensc-pkcs11.dll
From here follow the Mac instructions but use that file in place of
/usr/lib/ssh-keychain.dylib
One last wart: The SSH agent doesn't seem to work with PKCS11 providers, even in the latest beta version of OpenSSH for Windows (It always gives me an error adding the card).
You can either try to debug this (let me know if you get it working), give up like I did and use the .ssh/config option (typing your PIN every time you use the key), or hunt around for a Windows SSH client that has better PKCS11 support (one option is PuTTY SC).
My assumption is you are using the 64-bit versions of OpenSSH and OpenSC on Windows. That's waht I tested, and that's what I know works. If for some reason you have to install the 32-bit versions they should work fine, but OpenSC will probably install to "Program Files (32 bit)" or wherever your system is configured to put 32-bit applications. Update your paths as needed.
The following instructions are provided for reference, however they are not intended to be comprehensive. For full details refer to the OpenSSH documentation.
It's possible to use ssh-keygen to generate the authorized_keys (SSH pubkey)
formatted keys directly. To do this on a mac you would run:
ssh-keygen -D /usr/lib/ssh-keychain.dylib
As before substitute yout PKCS11 provider on Linux or Windows (and on Windows
you will need the version of OpenSSH that actually supports PKCS11.
This will return several keys (one for every authentication slot your card has apparently). If you have only configured Slot 9a that will be the only key returned. If not it appears that Slot 9a is always the first one returned, but it might vary so be prepared to test.
OpenSSH 6.8p1 and later supports multi-factor authentication.
To set this up all you need to do is add an AuthenticationMethods directive
to your OpenSSH server configuration (typically /etc/ssh/sshd_config
).
Typically you'll want something like:
AuthenticationMethods publickey,password
If you're using a more complex PAM configuration you can use:
AuthenticationMethods publickey,keyboard-interactive
You can even require two (different) public keys by specifying
AuthenticationMethods publickey,publickey
By using this in combination with "Match User" or "Match Group" directives it is possible to configure M-of-N key access for some accounts.
Two things to bear in mind here:
- The authentication methods are requested int he order listed
(if you specifypassword,publickey
you will be prompted for a password BEFORE the server checks for a key) - Specifying password or keyboard-interactive twice DOES NOT require
different authentication tokens
The SSH server is smart enough to remember what keys you've presented, but your password is always your password &keyboard-interactive
just hands the request off to PAM). You can of course require multiple authentication steps in your PAM configuration.
There is an excellent writeup on using a YubiKey in GPG Smartcard mode instead of PIV + PKCS11 mode. You can find it here: https://gist.github.com/lizthegrey/9c21673f33186a9cc775464afbdce820
GPG Smartcard mode has the advantage of allowing longer RSA keys and the use of GPG for general-purpose encryption, but requires additional software and configuration as detailed in that gist.
Those instructions also contain examples of how to allow users with hardware keys to use them as a single factor while requiring passwords for users whose keys are in a file on their computer. While this is a security improvement over trusting a single public key in an id_rsa file that can be stolen without being missing I would advise sticking to a design which requires a second factor of some kind - either a second public key (which may be a file) or a password.
List of revisions:
2020-03-18: Posted to GitHub GIST.