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 the 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

  1. Kumari Root EC CA
  2. Kumari Intermediate EC CA
  3. Kumari Root RSA CA
  4. Kumari Intermediate RSA CA

Note: The numbers in the list match the id values in the PKCS#11 URIs used to create the keys and certificates.

Note: To sign with the RSA CA, see this section.

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…

  1. Start step-ca
  2. In another window: step ca sign test.example.com.csr test.example.com.crt NOTE: This will prompt for a provisioner password. As this is only available locally, it is “password”.
  3. Inspect the new certificate: step certificate inspect --short test.example.com.crt
  4. 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:

Signing with the RSA CA

To sign with the RSA CA, you need to specify the CA and CA key when signing. This is because the default provisioner is configured to use the EC CA.

Start the step-ca with the RSA CA config:

step-ca ca-rsa.json

Then, when signing, specify the Root CA:

step ca sign --root "/Users/wkumari/.step/certs/root_ca_rsa.crt" nobby-drac.kumari.net.csr nobby-drac.kumari.net.pem

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: This email address is being protected from spambots. You need JavaScript enabled to view it. [ID: Odw5...Aisg]
  Valid from:  2026-03-08T08:43:38Z
          to:  2036-03-05T08:44:38Z

Creating a bundle certificate, and decrypting a key

Some devices expect a bundle certificate, which contains the full chain of certificates. To create a bundle certificate, cat the files together. $ cat exmaple.kumari.net.pem ../SmallStep/certs/intermediate_ca_ec.crt ../SmallStep/certs/root_ca_ec.crt > exmaple.kumari.net.bundle.pem

Note: The order of the certificates in the bundle is important - the leaf certificate should be first, followed by the intermediate, and then the root.

To decrypt a key, use the step CLI tool:

example.kumari.net.decrypted.key```

### List issued certificates

To list issued certificates, you can use the `step-badger` CLI tool.  This is a
third party tool, from
[step-badger](https://github.com/lukasz-lobocki/step-badger)

 The basic command:

```bash
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

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=<pin>;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 \\
   --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 "This email address is being protected from spambots. You need JavaScript enabled to view it." --x509-default-dur=43800h --x509-min-dur=5m --x509-max-dur=87600h

Creating the RSA Root Certificate

I needed to do this because some devices don’t support EC certificates, and instead require RSA. This is a bit more work, as the key generation is a bit more complex.

# Set the PKCS URI for the RSA key
xport PKCS_URI='pkcs11:module-path=/usr/local/lib/opensc-pkcs11.so;token=SmartCard-HSM;pin-value=<PIN>;id=3;object=root-ca-rsa'
# Create the key
step kms create --kty RSA --size 4096  'pkcs11:module-path=/usr/local/lib/opensc-pkcs11.so;token=SmartCard-HSM;pin-value=<PIN>;id=3;object=root-ca-rsa'

# Create the certificate (also with 25 year life):
step certificate create --profile root-ca --not-after 219000h \
--kms 'pkcs11:module-path=/usr/local/lib/opensc-pkcs11.so;token=SmartCard-HSM;pin-value=<PIN>;id=3;object=root-ca-rsa' \
--key 'pkcs11:id=3;object=root-ca-rsa'  "Kumari Root RSA CA" root_ca_rsa.crt

# Create the intermediate key and cert.
step kms create --kty RSA --size 2048 --kms "$PKCS_URI" "pkcs11:id=4;object=intermediate-ca-rsa"
step certificate create --profile intermediate-ca --not-after 219000h \
   --kms "$PKCS_URI" \
   --ca-kms "$PKCS_URI" \
   --ca root_ca_rsa.crt \
   --ca-key "pkcs11:id=3;object=root-ca-rsa" \
   --key "pkcs11:id=4;object=intermediate-ca-rsa" \
   "Kumari Intermediate RSA CA" intermediate_ca_rsa.crt