HSM/PKCS#11 Support
Ghostunnel has support for loading private keys from PKCS#11 modules, which should work with any hardware security module that exposes a PKCS#11 interface. An easy way to test the PKCS#11 interface for development purposes is with SoftHSM. Note that CGO is required in order for PKCS#11 support to work.
To import the server test key into SoftHSM, for example:
softhsm2-util --init-token \
--slot 0 \
--label ghostunnel-server \
--so-pin 1234 \
--pin 1234
softhsm2-util --id 01 \
--token ghostunnel-server \
--label ghostunnel-server \
--import test-keys/server-pkcs8.pem \
--so-pin 1234 \
--pin 1234
To launch Ghostunnel with the SoftHSM-backed PKCS#11 key:
ghostunnel server \
--cert test-keys/server-cert.pem \
--pkcs11-module /path/to/libsofthsm2.so \
--pkcs11-token-label ghostunnel-server \
--pkcs11-pin 1234 \
--listen localhost:8443 \
--target localhost:8080 \
--cacert test-keys/cacert.pem \
--allow-cn client
The --pkcs11-module, --pkcs11-token-label and --pkcs11-pin flags can be
used to select the private key to be used from the PKCS#11 module. It’s also possible
to use environment variables to set PKCS#11 options instead of flags (via
PKCS11_MODULE, PKCS11_TOKEN_LABEL and PKCS11_PIN), useful if you don’t want to show the PIN on the command line.
Note that --cert needs to point to the certificate chain that corresponds
to the private key in the PKCS#11 module, with the leaf certificate being the
first certificate in the chain (see
Certificate Formats). Ghostunnel currently
cannot read the certificate chain directly from the module.
Using a YubiKey
YubiKey 4 and 5 series support the PIV (FIPS 201) standard, which exposes a PKCS#11 interface via the YKCS11 module, so you can use a YubiKey to hold Ghostunnel’s private key in hardware.
Prerequisites
You’ll need yubico-piv-tool, which ships the CLI and the libykcs11
PKCS#11 module:
# macOS
brew install yubico-piv-tool
# Debian/Ubuntu
apt install yubico-piv-tool ykcs11
The module lives in different places depending on your platform:
| Platform | Typical path |
|---|---|
| macOS (Apple Silicon) | /opt/homebrew/lib/libykcs11.dylib |
| macOS (Intel) | /usr/local/lib/libykcs11.dylib |
| Linux (x86_64) | /usr/lib/x86_64-linux-gnu/libykcs11.so or /usr/local/lib/libykcs11.so |
PIV slots
YubiKey PIV has several key slots. For TLS with Ghostunnel, you’ll usually want slot 9a (Authentication):
| Slot | Purpose | Typical use |
|---|---|---|
| 9a | Authentication | TLS client/server certs |
| 9c | Digital Signature | Code/document signing |
| 9d | Key Management | Encryption |
| 9e | Card Authentication | Physical access |
Generating a Key and Certificate
Generate a key pair on the YubiKey itself (the private key never leaves the device):
# Generate an RSA 2048 key in slot 9a
yubico-piv-tool -s 9a -a generate -A RSA2048 -o public-key.pem
# Create a certificate signing request (CSR)
yubico-piv-tool -s 9a -a verify-pin -a request-certificate \
-S '/CN=my-server/' -i public-key.pem -o csr.pem
Sign the CSR with your CA, then import the signed certificate back:
yubico-piv-tool -s 9a -a import-certificate -i server-cert.pem
Exporting the Certificate for Ghostunnel
Ghostunnel reads the certificate chain from disk, not from the PKCS#11 module, so you’ll need to export it:
yubico-piv-tool -s 9a -a read-certificate -o server-cert.pem
If your CA has an intermediate, concatenate them into a chain (leaf first):
cat server-cert.pem intermediate.pem > chain.pem
Launching Ghostunnel with a YubiKey
ghostunnel server \
--cert chain.pem \
--pkcs11-module /opt/homebrew/lib/libykcs11.dylib \
--pkcs11-token-label "YubiKey PIV #12345678" \
--pkcs11-pin 123456 \
--listen localhost:8443 \
--target localhost:8080 \
--cacert ca-cert.pem \
--allow-cn client
The default PIV PIN is 123456. Change it before doing anything real. To
keep the PIN off the command line, use the PKCS11_PIN environment variable
instead of --pkcs11-pin.
To find the correct token label for your YubiKey:
pkcs11-tool --module /opt/homebrew/lib/libykcs11.dylib -L
Debugging
If things aren’t working, set YKCS11_DBG (values 1–9) for verbose output
from the YKCS11 module:
YKCS11_DBG=1 ghostunnel server ...
pkcs11-tool is also handy for poking around on the YubiKey:
# List available slots/tokens
pkcs11-tool --module /path/to/libykcs11.dylib -L
# List objects (keys, certificates) on the token
pkcs11-tool --module /path/to/libykcs11.dylib -O
Certificate Hotswapping
When using PKCS#11, certificate hotswapping (via SIGHUP/SIGUSR1 or
--timed-reload) reloads only the certificate from disk. The private key
in the HSM stays put, so the new certificate still needs to match the key
that was loaded from the HSM.
Note that Landlock sandboxing is automatically disabled when PKCS#11 is used, as PKCS#11 modules are opaque shared libraries that may need access to arbitrary files and sockets.
Inspecting PKCS#11 State
If you need to inspect the state of a PKCS#11 module/token, we recommend the
pkcs11-tool utility from OpenSC. For example, it can be used
to list slots or read certificate(s) from a module:
# List slots on a module
pkcs11-tool --module $MODULE -L
# Show certificates (if any) available
pkcs11-tool --module $MODULE -O -y cert
# Read certificate chain given a label
pkcs11-tool --module $MODULE --label $LABEL --read-object -y cert