Skip to content

Repository files navigation

Using a Yubikey for SSH CA Key Storage and Certificate Signing

This project provides a set of bash scripts for managing SSH CA signing keys using the PIV application of a Yubikey security device. The tools allow you to do the following:

  • Create user and host CA keys and import them into one or more Yubikeys.

  • Change the PIN, PUK and Management codes for the Yubikey to randomly generated values

  • Generate user and host SSH certificates by signing SSH public keys using the CA key stored in the Yubikey.

Generate Passphrase for SSH CA Keys

The diceware application can be used generate strong passphrases for your SSH CA keys:

$ sudo apt install diceware
$ diceware -d ' '

This is only one of many ways to generate strong passphrases.

Create SSH CA Keys and Setup Yubikey

First, clone this repo to the server system:

$ git clone https://github.com/openavr/sshca-yk.git
$ cd sshca-yk

To generate the User and Host SSH CA keys and load them into a Yubikey:

Usage: ./ca-create.sh <org-domain> <org-common-name>

NOTE: The keys could also be generated inside the Yubikey (which is much more secure since they can not be extracted), but leaves you with no backup should the Yubikey fail or get lost. As such, the keys are generated externally and then imported into the Yubikey. This allows the same keys to be imported into multiple Yubikeys.

For example, for the example.com domain, with a common name of Example Inc (this will prompt you to enter the passphrase for the keys):

$ ./ca-create.sh example.com 'Example Inc'

The generated private keys are now on-disk and in the Yubikey. The on-disk copies must be protected and not shared.

Verify the contents of the Yubikey:

$ ykman piv info
...
Slot 84 (RETIRED3):
  Private key type: ED25519
  Public key type:  ED25519
  Subject DN:       CN=Example Inc User SSH CA,O=example.com
  Issuer DN:        CN=Example Inc User SSH CA,O=example.com
  Serial:           54:6d:90:a7:42:e7:56:d1:ae:92:e3:84:a4:82:33:48:a6:ec:16:82
  Fingerprint:      7fa671502d10506db173093e36fae5fcf4a0062de946037903e564080e041867
  Not before:       2026-08-09T16:10:31+00:00
  Not after:        2026-11-07T16:10:31+00:00
...

Set the PIV access codes on the Yubikey so that they are not the default values:

$ ./ca-yk-set-access.sh

You can setup another Yubikey with the same keys by plugging in a different Yubikey and repeating the process:

$ ./ca-create.sh example.com 'Example Inc'
$ ./ca-yk-set-access.sh

Running the ca-create.sh multiple times will not generate new keys given the same arguments, but note that it may fail if run again after the PIV access codes have been changed on the Yubikey due to the defaults no longer being usable, or the access codes were modified.

Generate an authorized_keys_ca file that has entries you can copy to your ~/.ssh/authorized_keys file on the server that you want to allow users to log into using certificates:

$ ./generate-auth-keys.sh example.org

The generated authorized_keys_ca can be copied to any server as it does not contain any sensitive material. You can also copy only the keys entries that you desire from the authorized_keys_ca file instead of using theentire file.

Signing User or Host Keys

Generate user certificates with either of the following:

$ ./ca-sign-user.sh example.com jsmith
$ ./ca-sign-user.sh example.com jsmith ~/.ssh/id_ed25519_jsmith

Generate host certificates with:

$ ./ca-sign-host.sh myserver example.com /etc/ssh/ssh_host_ed25519_key.pub

Signing Using a SSH Agent

You can also make use of an SSH agent to ease signing operations. Loading the pkcs#11 module into the agent with ssh-add:

$ ssh-add -s /usr/lib/x86_64-linux-gnu/libykcs11.so

That will ask for the PIN to unlock the keys in the Yubikey and subsequent invocations of the signing scripts will not ask you to re-enter the PIN.

Remove the keys from the agent with:

$ ssh-add -e /usr/lib/x86_64-linux-gnu/libykcs11.so

Server Side User SSH CA Setup

Copy the User SSH CA line from the generated authorized_keys_ca file into your ~/.authorized_keys file on the server(s).

Alternatively, you could install the User SSH CA public key globally so that it can be used for all user accounts by adding it to the TrustedUserCAKeys entry in the /etc/ssh/sshd_config file. See the sshd_config(5) man page for more details.

$ sudo cp keys-ca/example.com/id_ed25519_user_ca.pub /etc/ssh
$ echo "TrustedUserCAKeys /etc/ssh/id_ed25519_user_ca.pub" \
    | sudo tee /etc/ssh/sshd_config.d/user_ca.conf
$ sudo systemctl restart sshd

The target user account name on the server should be at least one of the principals in the certificate file.

The server side user account is now setup to accept logins from clients using certificates signed by the SSH User CA.

Client Side User SSH CA Setup

Clone this repo to the client system:

$ git clone https://github.com/openavr/sshca-yk.git
$ cd sshca-yk

Plug the Yubikey into the client system.

Extract the CA public key from the Yubikey:

$ ykman piv info
$ ssh-keygen -D /usr/lib/x86_64-linux-gnu/libykcs11.so \
    | grep 'Retired Key 3' > keys-ca/example.com/id_ed25519_user_ca.pub

Generate and sign a user ssh key pair and certificate:

$ ./ca-sign-user.sh example.com ${USER}

You should now be able to login to the server as ${USER}:

$ ssh -i ./keys-user/id_ed25519_${USER} <server>

You can also create the key and sign the cert in your ~/.ssh directory:

$ ./ca-sign-user.sh example.com ${USER} ~/.ssh/id_ed25519_${USER}

Generating an ed25519 SSH Key and Loading It Into a Yubikey

Background

By default, openssh generates ed25519 keys. Yubikeys can be used to store those keys and provide cryptographics operations on those keys using PKCS#11 API's.

Generating ed25519 keys with openssh is trivial, but importing them into a Yubikey is not possible without converting the format of the keys from openssh format into openssl PEM format. In theory, the conversion should be a trivial openssh command, but alas, running that command failed with openssh stating that the PEM format was not supported for the ed25519 key type.

This has been frustrating for the past few years, but it is now possible on Linux with:

  • Yubikey firmware >= 5.7.0
  • OpenSSL >= 3.5.0
  • OpenSSH >= 10.3p1

The following instructions show you how to do manually what the scripts in this project help to automate.

Debian OS Setup

The format of the private generated by openssh can not be imported directly into a Yubikey, it must be converted first.

You must use openssh >= 10.3p1 in order to be able to generate ed25519 keys and convert them to PEM or PKCS8 format that can be loaded into Yubikey.

For Debian-13 (Trixie), you need to install the openssh tools using debian backports. Setup debian backports with the instructions here:

Once backports is setup, install the newer version of openssh:

$ sudo apt update
$ sudo apt install \
    openssh-client/trixie-backports \
    openssh-server/trixie-backports \
    openssh-sftp-server/trixie-backports

You only need openssh >= 10.3p1 if you are loading the CA or user keys into the Yubikey, and do not need the newer version if you are only using the Yubikey to sign user or host certificates.

Install the Yubikey tools:

$ sudo apt install yubikey-manager ykcs11 yubico-piv-tool

Generate SSH Key And Import Into Yubikey

NOTE: The -N '' will generate a key without a passphrase which is probably not what you want.

Generate a ed25519 key pair:

$ ssh-keygen -t ed25519 -N '' -f id_ed25519_foo

Convert the private key to a format that can be imported into a Yubikey:

$ cp id_ed25519_foo id_ed25519_foo.key
$ ssh-keygen -p -m PKCS8 -N '' -f id_ed25519_foo_key.pem

Import the private key into a Yubikey:

$ ykman piv keys import 85 id_ed25519_foo_key.pem
$ ykman piv info

Checking if Keys Match

To verify is a private key and a public match, use this:

# match if no differences and exit code of 0
$ diff <(ssh-keygen -l -v -f $sshkeyfile) <(ssh-keygen -l -v -f $sshpubfile)

To see if a public key matches the private key stored in a Yubikey slot, you first need to dump all of the public keys stored in the Yubikey. This can be done with the following command:

$ ssh-keygen -D /usr/lib/x86_64-linux-gnu/libykcs11.so

Then you can compare against another public key, but this is probably not needed since now you have the public keys of the private keys in the Yubikey and can just use them.

Required Dependencies

Run the following command to install basic tool dependencies needed for these scripts:

$ sudo apt install ykcs11 yubico-piv-tool yubikey-manager libyubikey-udev

About

Utility scripts for using Yubikeys to store SSH user and host Certificate Authority keys.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages