Using OpenSSH Certificates for Host Login
OpenSSH supports a proprietary version of certificates that allow simple login to hosts.
Traditional Method
The usual way to enable a user U
to access a specific host H
using SSH is to copy the public key of U
in a file on H
(typically called authorized_keys
).
This method suffers from a lack of generality. If another user U'
were to be given access to H
, their public key should also be copied in that same file. At the same time, if U
were to be given access to a different host H'
, their public key would have to be added to an equivalent file on that host.
While various automatic provisioning systems have been devised, those still represent a workaround rather than a solution to the problem.
OpenSSH CA
Since version 5.4 (released 2010-03-08) OpenSSH has had support for so-called OpenSSH Certificates.
By using these, only one OpenSSH CA public key has to be copied onto the target host. At that point any user can be granted access to any such host by giving them a file that contains the following information: their own public key, a validity period, a list of usernames that the user is allowed to login as, and a digital signature over the whole content created using the private key of the SSH CA.
This file, the SSH Certificate, is then automatically presented to the SSH server by the SSH client of the user as part of the login process.
OpenSSH Certificates with YubiHSM 2
The private key of an SSH CA is a regular private key and can be stored on a YubiHSM 2. OpenSSH has built-in support for signing SSH Certificates using CA private keys that reside on a hardware token through the PKCS#11 interface.
The YubiHSM 2 also has specific support for signing SSH Certificates using an RSA CA key. This guide will also describe how to leverage that.
Example: OpenSSH built-in support for Signing SSH certificates
Signing SSH certificates is performed with OpenSSH’s ssh-keygen
command using the -s ca_key
option. The ca_key
specifies the key file containing the signing key. The signing key can be stored in an HSM, in which case the key file only contains the public part of the signing key. The public key is used to locate the corresponding private key on the HSM through the PKCS#11 interface. The PKCS#11 module to use is specified with the -D
option.
Step1: | Create an SSH CA key on the HSM, export the CA public key, and convert the public key into PKCS8 format for use with OpenSSH. $ yubihsm-shell -a generate-asymmetric-key --authkey=0x0001
-p password -i 0x000a -l "SSH_CA_Key" -c "sign-pkcs" -A rsa2048
Using default connector URL: http://127.0.0.1:12345
Session keepalive set up to run every 15 seconds
Created session 1
Generated Asymmetric key 0x000a
$ yubihsm-shell -p password --authkey=0x0001 -a get-public-key
-i 0x000a --out ca_pub.pem
Using default connector URL: http://127.0.0.1:12345
Session keepalive set up to run every 15 seconds
Created session 1
$ ssh-keygen -i -f ca_pub.pem -m PKCS8 > ca.pub
Note The CA key needs capability |
---|---|
Step 2: | Sign the user’s pubkey in the file $ ssh-keygen -s ca.pub -D /usr/local/lib/pkcs11/yubihsm_pkcs11.dylib
-I key_id id_rsa.pub
Enter PIN for 'YubiHSM':
Signed user key id_rsa-cert.pub: id "key_id" serial 0 valid forever
Note The PIN needs to be prefixed with the ID of the authentication-key in order for The signed SSH certificate is generated in the file |
Signing SSH Certificate Requests
Instead of directly signing a user’s SSH pubkey directly, the YubiHSM 2 can also be used to sign SSH pubkeys only when a number of conditions are met. This scenario is discussed in the rest of this document.
High-level Description and components
A YubiHSM 2 device is able to sign OpenSSH public keys when those are submitted to the device as part of a specific format that we call OpenSSH Certificate Request
.
Such a request is granted (i.e. the signature is computed and released), if and only if the following two requirements are fulfilled:
The user who sends the request to the device has the right privileges to access the OpenSSH CA private key on the device.
This is fulfilled by making sure that the user submitting the request (who may not be the same one who generates the request) can establish a Session with the device through an Authentication Key that has access to the necessary Domains and has the necessary Capability set.
The OpenSSH Certificate Request meets a series of pre-defined constraints.
This is fulfilled by encoding those pre-defined constraints in an object with Type
Template
and AlgorithmSSH Template
.
SSH Template
An SSH Template
is a binary object that can be used to restrict how and when an SSH CA private key should be used to sign SSH Certificate Requests.
This is a binary object that encodes a series of constraints. Its format is a collection of Tag-Length-Value tuples whose meaning is described below:
Tag Value | Tag Description |
---|---|
0x01 | Timestamp key algorithm |
0x02 | Timestamp public key |
0x03 | CA key white-list |
0x04 | Not before |
0x05 | Not after |
0x06 | Principals black-list |
The individual tags are further explained below.
Timestamp Key Algorithm – The ALGORITHMS of the public key used to verify timestamp signatures.
Timestamp Public Key – The public key used to verify timestamp signatures.
CA Key White-list – The list of Object IDs describing which Asymmetric Keys can be used with this template.
Not Before – The Not Before time offset to be applied to the current time. If a request contains a time value that is before this computed timestamp, an error will be returned.
Not After – The Not After time offset to be applied to the current time. If a request contains a time value that is after this computed timestamp, an error will be returned.
Principals Black-list – The nul-separated, nul-terminated list of Principals (user names) for which a certificate will not be issued.
Example template – A hex-dump of an example template file is shown below:
01 0001 09 02 0100 cb2702...d71081f1d1 03 0002 000a 04 0004 000012c0 05 0004 00008ca0 06 0005 726f6f7400
This template file contains, in order:
- Timestamp Key Algorithm 9 (RSA 2048)
- Timestamp public key (256 bytes)
- CA Key whitelist containing the single Key ID 0x000a
- A Not before offset of 300 seconds (5 minutes)
- A Not before offset of 36000 seconds (10 hours)
- A principal blacklist containing the principal
root
Although not officially supported, templates can be generated using yubihsm-ssh-tool.
For instance, the above template file and the embedded timestamp key are generated using:
$ openssl genrsa -out timestamp.pem
Generating RSA private key, 2048 bit long modulus
.................................+++
........................................+++
e is 65537 (0x10001)
$ openssl rsa -pubout -in timestamp.pem -out timestamp_pub.pem
writing RSA key
$ pipenv run yubihsm-ssh-tool templ -T timestamp_pub.pem -k 10 -b 300 -a 36000 -p root
Here, the file timestamp_pub.pem
contains the timestamp certificate public key, the CA key ID is 10, certificates should only be issued if their validity is at most 5 minutes in the past (to accomodate for clock skew) and at most 10 hours in the future. Also, certificates for user root
are not allowed.
SSH Certificate Request
An SSH certificate format is defined by OpenSSH but it is not too dissimilar from an X.509 certificate. At its core it is a collection of attributes, a time period, a public key and a signature over all the data.
An SSH Certificate Request is the set of information that must be sent to a YubiHSM 2 so that it can generate the aforementioned signature. This consists of all the data present in the certificate (excluding the signature).
For a description, see the ssh-rsa-cert-v01@openssh.com
key format in the OpenSSH specs.
Signing an SSH Certificate Request
After an SSH Template has been stored on the YubiHSM 2 and an SSH Certificate Request has been created, it can be sent to the device for signing.
This is done by issuing the Sign SSH Certificate Command. The parameters required are:
- Object ID of the SSH CA key which has already been stored on the device
- Object ID of the SSH Template to use in order to validate the request
- Algorithm to use to produce the certificate signature
- timestamp with the definition of
Now
- signature
ST
over the SSH Certificate Request and the timestamp- SSH Certificate Request
After the command is issued, the following steps take place in the YubiHSM 2. First the signature ST
is verified using the public key present within the specified SSH Template. If the verification is successful, the value of Now
is recorded. Next the SSH Certificate Request is parsed to extract the Not Before
and Not After
timestamps together with the list of Principals. The following checks are then performed:
- ID of the SSH CA key must appear in the SSH CA key white-list present in the SSH Template.
Not Before
timestamp in the SSH Certificate Request must be greater than or equal toNow
plus theNot Before
offset specified in the SSH Template.Not After
timestamp in the SSH Certificate Request must be less than or equal toNow
plus theNot After
offset specified in the SSH Template.- That none of the Principals specified in the SSH Certificate Request must appear in the Principals black-list SSH Template.
If all the constraints were fulfilled, the YubiHSM 2 produces a signature using the Algorithm specified in the command. This signature can be appended to the SSH Certificate Request to produce a valid SSH Certificate.
Example request
Although not officially supported, requests can be generated using yubihsm-ssh-tool:
$ pipenv run yubihsm-ssh-tool req -s ca_pub.pem -t timestamp.pem
-I user-identity -n username -V -5h:+5h id_rsa.pub
Example: Signing SSH certificates using templates and signing requests
Below is an example of signing SSH certificates using templates and certificate requests.
Step 1: | Create an SSH CA key on the HSM, and export the CA public key. $ yubihsm-shell -a generate-asymmetric-key --authkey=0x0001
-p password -i 10 -l "SSH_CA_Key" -c "sign-ssh-certificate" -A rsa2048
Using default connector URL: http://127.0.0.1:12345
Session keepalive set up to run every 15 seconds
Created session 1
Generated Asymmetric key 0x000a
$ yubihsm-shell -p password --authkey=0x0001 -a get-public-key
-i 10 --out ca_pub.pem
Using default connector URL: http://127.0.0.1:12345
Session keepalive set up to run every 15 seconds
Created session 1
Note This time, the CA key needs capability |
---|---|
Step 2: | Create the template file and store the template in the HSM as an object of type $ pipenv run yubihsm-ssh-tool templ -T timestamp_pub.pem -k 10
-b 36000 -a 36000 -p root
$ yubihsm-shell -a put-template -p password -i 20 -l "SSH_Template"
-A template-ssh --in templ.dat
Using default connector URL: http://127.0.0.1:12345
Session keepalive set up to run every 15 seconds
Created session 1
Stored Template object 0x0014
|
Step 3: | Generate a certificate signing request for user $ pipenv run yubihsm-ssh-tool req -s ca_pub.pem -t timestamp.pem
-I user-identity -n username -V -5h:+5h id_rsa.pub
Hash is: b'95dd317189b5e392481de896e7f111228b76d6efe3daa344c2da28
19927a05cb'
|
Step 4: | Sign the certificate request using the CA key on the HSM. $ yubihsm-shell -a sign-ssh-certificate -p password -i 10
--template-id 20 -A rsa-pkcs1-sha256 --in req.dat --out id_rsa-cert.pub
Using default connector URL: http://127.0.0.1:12345
Session keepalive set up to run every 15 seconds
Created session 1
The signed SSH certificate is generated in the file |
Example: constraint violation
To illustrate what happens when the constraints specified in the certificate template are violated, for instance when a certificate is requested for the root
user.
$ pipenv run yubihsm-ssh-tool req -s ca_pub.pem -t timestamp.pem -I user-identity -n root -V -5h:+5h id_rsa.pub
Hash is: b'b75d30392a5ea5887affceb593154d2cc860f76f7bbc82757ec3fa20cd2a4d63'
$ yubihsm-shell -a sign-ssh-certificate -p password -i 10 --template-id 20 -A rsa-pkcs1-sha256 --in req.dat --out id_rsa-cert.pub
Using default connector URL: http://127.0.0.1:12345
Session keepalive set up to run every 15 seconds
Created session 1
Failed to get certificate signature: SSH CA constraint violation
Unable to get ssh certificate