Skip to content

Instantly share code, notes, and snippets.

@joostd
Last active July 18, 2024 13:45
Show Gist options
  • Save joostd/84761ceef2c6b856e0d417e31d82e626 to your computer and use it in GitHub Desktop.
Save joostd/84761ceef2c6b856e0d417e31d82e626 to your computer and use it in GitHub Desktop.
An example setup using OpenSSL v3.x with a PKCS#11 engine using a YubiHSM

YubiHSM with OpenSSL v3 and pkcs11-provider

OpenSSL v1.x uses the engine API to support HSMs. The OpenSC project provides a PKCS#11 engine, suitable for using HSMs that provide a PKCS#11 module. OpenSSL v1 is however deprecated, and in OpenSSL v3 the engine concept is replaced with that of a provider

Instead of using OpenSC's PKCS#11 engine, you can use pkcs11-provider with OpenSSL v3.x

This document describes how to use the YubiHSM with OpenSSL v3 and this provider.

Testing with Docker

Currently (July 2024), pkcs11-provider is not distributed yet with various Linux distributions. It is however in Debian-unstable.

For this test, we are using Docker with a recent Debian sid image:

docker run --rm -it --name pkcs11-provider-test debian:sid bash

Build and install yubihsm-shell

First update the list of available packages and install package management tools:

apt update
apt install -y apt-utils

Install git and clone the YubiHSM SDK repository to build from source:

apt install -y git
git clone https://github.com/Yubico/yubihsm-shell.git
cd yubihsm-shell/

Follow the build instructions from the SDK's README file:

mkdir build
cd build/
apt install -y build-essential cmake gengetopt help2man libcurl4-openssl-dev libedit-dev libpcsclite-dev libssl-dev libusb-1.0-0-dev pkg-config
cmake ..
cmake --build .

In case you encounter this error message:

/usr/include/PCSC/winscard.h:44:10: fatal error: pcsclite.h: No such file or directory

there is something wrong with your install. Probably an issue with pkg-config.

A quick workaround is to edit the .h files in /usr/include/PCSC:

sed -i'' 's#<pcsclite.h#<PCSC/pcsclite.h#;s#<wintypes.h#<PCSC/wintypes.h#' /usr/include/PCSC/*.h 

When the build is succesful, install the binaries:

make install

You shound now be able to tun the YubiHSM shell:

yubihsm-shell -h

Configure YubiHSM

On the docker host, start yubihsm-connector, so we can connect to it remotely over HTTP.

to verify the connector can be accessed, retrieve the status page:

apt install -y curl
curl http://host.docker.internal:12345/connector/status

this should return status=OK.

Create the YubiHSM configuration file pointing to your connector, and make its location known to YubiHSM's PKCS#11 module using the appropriate environment variable:

echo "connector=http://host.docker.internal:12345" > yubihsm.conf
export YUBIHSM_PKCS11_CONF=$PWD/yubihsm.conf 

Generate an RSA key pair

Assume the YubiHSM has been factory reset with the default authentication password. Together with its ID, this will be the PKCS#11 user PIN:

export PIN=0001password

Define an environment variable to point to the YibiHSM PKCS#11 module On Debian, this is:

export PKCS11_PROVIDER_MODULE=/usr/local/lib/pkcs11/yubihsm_pkcs11.so 

Install pkcs11-tool (part of OpenSC) to generate keys (and simultaneously test the YubiHSM PKCS#11 module setup):

apt install -y opensc
pkcs11-tool --module $PKCS11_PROVIDER_MODULE --login --pin $PIN --keypairgen --key-type rsa:2048 --label "my_key" --usage-sign

We use the label my_key to refer to this key.

Install the PKCS#11 Provider

Install pkcs11-provider:

apt install -y pkcs11-provider

This should install the provider in OpenSSL's modules directory. The location of that directory can be retrieved with:

openssl version -m

This should output something like:

MODULESDIR: "/usr/lib/aarch64-linux-gnu/ossl-modules"

Verify that the file /usr/lib/aarch64-linux-gnu/ossl-modules/pkcs11.so exists.

OpenSSL

OpenSSL v3 should already be installed on your system.

To interface with the PKCS#11 provider, we need to use a configuration file:

cat << EOF > openssl.cnf
HOME = .

openssl_conf = openssl_init

[openssl_init]
providers = provider_sect

[provider_sect]
default = default_sect
pkcs11 = pkcs11_sect

[default_sect]
activate = 1

[pkcs11_sect]
module = /usr/lib/aarch64-linux-gnu/ossl-modules/pkcs11.so
pkcs11-module-path = $PKCS11_PROVIDER_MODULE
pkcs11-module-token-pin = $PWD/pinfile.txt
activate = 1
EOF

Store the PIN in a file (not the best option, but fine for this test):

echo $PIN > pinfile.txt

Use a pkcs11 URI to refer to the key we generated earlier. Note the use of the key's label, my_key:

export KEY="pkcs11:token=YubiHSM;object=my_key;type=private;pin-value=$PIN"

Generate a self-signed certificate for the key stored in the HSM, using OpenSSL, the PKCS#11 provider, and the YubiHSM PKCS#11 module, according to the configuration file:

openssl req -config ./openssl.cnf -new -x509 -days 365 -subj '/CN=localhost/' -sha256 -key "$KEY" -out cert.pem

Use the RSA key on the HSM to run a test web server

Use OpenSSL as a simple HTTPS server with the generated certificate and the key stored in the HSM:

OPENSSL_CONF=./openssl.cnf openssl s_server -cert cert.pem -key $KEY  -www

As a client, use curl to connect with the web server.

docker exec pkcs11-provider-test curl -s https://localhost:4433/ -k

This should succesfully establish an HTTPS connection with the web server.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment