This is a quick cheatsheet for using Smallstep CA. It is not meant to be a comprehensive guide, but rather a quick reference for myself. It starts with the common tasks, but contains install and setup information as the end of the document.
Overview
This setup creates a Certificate Authority using the Smallstep CA, and a Nitrokey HSM 2 to protect the keying material.
I do this so that I can login to things like Opengear terminal servers, Dell
iDRAC interfaces, Proxmox machines and similar without getting the annoying
NET::ERR_CERT_AUTHORITY_INVALID error message from Chrome.
This really is not intended to replace more secure solutions, but instead as a convenience.
Note that the Smallstep support for PKCS
#11 is still a beta, and requires
adding the step-kms-plugin as
well as building a local
copy
of step-ca
My Certificates
Common tasks
Signing a CSR
This will take a Certificate Signing Request and generate a certificate. In
order to keep these organized I store them in ~/src/code/CA/certificates.
Because I am using the PKCS11 interface, I cannot use “offline” mode, and
instead use the (locally compiled, with PKCS#11 support) step-ca program.
This means that I need to start Step CA, and then use step to actually sign
the certificates. Don’t forget to stop step-ca after this. It is configured
to only listen on 127.0.0.1:8100, so it’s not really the end of the world if I
do forget, but…
- Start
step-ca - In another window:
step ca sign test.example.com.csr test.example.com.crtNOTE: This will prompt for a provisioner password. As this is only available locally, it is “password”. - Inspect the new certificate:
step certificate inspect --short test.example.com.crt - Stop
step-ca
Creating a certificate without a CSR
Sometimes devices don’t have an easy way to make a CSR, and instead expect you
to make a key and certificate for them. If this is the case, step can create
a key and CSR, and then use the above to sign it.
$ step certificate create --csr --san localhost --san example.com 192.0.2.1 test.example.com.csr test.kumari.net.key
Please enter the password to encrypt the private key:
Inspecting a certificate
To inspect a certificate, you can use the step certificate inspect CLI tool.
The basic command:
step certificate inspect --short test.example.com.crt ✔
X.509v3 TLS Certificate (ECDSA P-256) [Serial: 2898...4074]
Subject: 127.0.0.1
localhost
macbook
Issuer: My Intermediate CA
Provisioner: [email protected] [ID: Odw5...Aisg]
Valid from: 2026-03-08T08:43:38Z
to: 2036-03-05T08:44:38Z
List issued certificates
To list issued certificates, you can use the step-badger CLI tool. This is a
third party tool, from
step-badger
The basic command:
step-badger x509Certs ~/.step/db
Serial number Subject Start Finish Validity
302993289828619663782218509723082042948 CN=test.example.com 2026-03-08T04:05:50Z 2026-03-09T04:06:50Z Valid
288747816944534935195190911414687768787 CN=test.example.com 2026-03-08T04:06:41Z 2026-03-09T04:07:41Z Valid
Note: Because this uses the database, step-ca must be stopped.
Troubleshooting
Forgot to plug in the HSM
This bit me once - I fetched the HSM and connected the adapter - but forgot to
actually connect the HSM to the adapter. The error message is clear though:
error initializing PKCS#11: could not find PKCS#11 token
$ step-ca
badger 2026/03/29 20:04:08 INFO: All 1 tables opened in 0s
badger 2026/03/29 20:04:08 INFO: Replaying file id: 0 at offset: 20127
badger 2026/03/29 20:04:08 INFO: Replay took: 1µs
error initializing PKCS#11: could not find PKCS#11 token
OS X Update breaks PKCS#11
This is a known issue with OS X updates - see Nitrokey HSM Getting Started for more information.
Symptoms
$ step-ca
error initializing PKCS#11: could not find PKCS#11 token
$ pkcs15-tool -D
Using reader with a card: Nitrokey Nitrokey HSM
Failed to connect to card: Unresponsive card (correctly inserted?)
Solution
The problem can be fixed by either copying /usr/libexec/SmartCardServices to /usr/local/libexec/SmartCardServices
sudo mkdir -p /usr/local/libexec/SmartCardServices/drivers
sudo cp -a /usr/libexec/SmartCardServices/drivers/ifd-ccid.bundle /usr/local/libexec/SmartCardServices/drivers
Note: This is a known issue with OS X updates - see Nitrokey HSM Getting Started for more information.
Note: Ignore the errors from chown / permissions…
Setup and installation
Initializing the Nitrokey HSM
sc-hsm-tool --initialize --so-pin <16 char hex> --pin <6 char pin>
Printing the key info
$ pkcs15-tool -D
Using reader with a card: Nitrokey Nitrokey HSM
PKCS#15 Card [SmartCard-HSM]:
Version : 0
Serial number : DENKxxx
Manufacturer ID: www.CardContact.de
Flags :
PIN [UserPIN]
Object Flags : [0x03], private, modifiable
Auth ID : 02
[...]
Tries left : 3
PIN [SOPIN]
Object Flags : [0x01], private
ID : 02
[...]
Tries left : 15
Make things simpler - save
export PKCS_URI='pkcs11:module-path=/usr/local/lib/opensc-pkcs11.so;token=SmartCard-HSM;pin-value=<PIN>;id=1;object=root-ca-ec'
Creating the CA key
step kms create 'pkcs11:module-path=/usr/local/lib/opensc-pkcs11.so;token=SmartCard-HSM;pin-value=<KEY>;id=1;object=root-ca-ec'
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEoKX9OFloafydMUzgJJkvE1iN7DQr
IPAE6BBgdXuWERsGWkpKx+79mPO8NwBs3Yjv+fRL2/RATvIOoaBthaX42g==
-----END PUBLIC KEY-----
Creating the Root Certificate
step certificate create --profile root-ca --not-after 219000h \
--kms
'pkcs11:module-path=/usr/local/lib/opensc-pkcs11.so;token=SmartCard-HSM;pin-value=<6 char key>;id=1;object=root-ca-ec'\
--key 'pkcs11:id=1;object=root-ca-ec' "Kumari Root EC CA" root_ca_ec.crt
This creates a root certificate with a 25 year validity (219000h)
Create the Intermediate Certificate
$ step kms create --kms "$PKCS_URI" "pkcs11:id=2;object=intermediate-ca-ec"
# And the certificate (also with 25 year life):
$ step certificate create --profile intermediate-ca --not-after 219000h \\ 1 ✘ 15s
--kms "$PKCS_URI" \\
--ca-kms "$PKCS_URI" \\
--ca root_ca_ec.crt \\
--ca-key "pkcs11:id=1;object=root-ca-ec" \\
--key "pkcs11:id=2;object=intermediate-ca-ec" \\
"Kumari Intermediate EC CA" intermediate_ca_ec.crt
Setting defaults
# Defaults - 5year, max 10 year.
step ca provisioner update "[email protected]" --x509-default-dur=43800h --x509-min-dur=5m --x509-max-dur=87600h