SoftHSM 2.4.0 on Ubuntu 18.10

Installing the software

Package list:

nginx :: ~ » apt install -y softhsm2 opensc gnutls-bin libengine-pkcs11-openssl1.1
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following additional packages will be installed:
  libccid libgnutls-dane0 libopts25 libpcsclite1 libsofthsm2 libunbound2 opensc-pkcs11 p11-kit p11-kit-modules pcscd softhsm2-common
Suggested packages:
  pcmciautils dns-root-data
The following NEW packages will be installed:
  gnutls-bin libccid libengine-pkcs11-openssl1.1 libgnutls-dane0 libopts25 libpcsclite1 libsofthsm2 libunbound2 opensc opensc-pkcs11 p11-kit p11-kit-modules pcscd softhsm2
  softhsm2-common
0 upgraded, 15 newly installed, 0 to remove and 2 not upgraded.
[... cut off rest of the output here ...]

Preparing a token ("device"):

Now let's create/initialize a token. For now, we will label the new token demo:

softhsm2-util --init-token --slot 0 --label "demo"

It will ask you for the "Security Officer PIN" and the "User PIN".

An example:

nginx :: ~ » p11tool --list-tokens
Token 0:
        URL: pkcs11:model=p11-kit-trust;manufacturer=PKCS%2311%20Kit;serial=1;token=System%20Trust
        Label: System Trust
        Type: Trust module
        Flags: uPIN uninitialized
        Manufacturer: PKCS#11 Kit
        Model: p11-kit-trust
        Serial: 1
        Module: p11-kit-trust.so

nginx :: ~ » softhsm2-util --init-token --slot 0 --label "demo"
=== SO PIN (4-255 characters) ===
Please enter SO PIN: **********
Please reenter SO PIN: **********
=== User PIN (4-255 characters) ===
Please enter user PIN: ******
Please reenter user PIN: ******
The token has been initialized and is reassigned to slot 1530022663
nginx :: ~ » p11tool --list-tokens
Token 0:
        URL: pkcs11:model=p11-kit-trust;manufacturer=PKCS%2311%20Kit;serial=1;token=System%20Trust
        Label: System Trust
        Type: Trust module
        Flags: uPIN uninitialized
        Manufacturer: PKCS#11 Kit
        Model: p11-kit-trust
        Serial: 1
        Module: p11-kit-trust.so

Token 1:
        URL: pkcs11:model=SoftHSM%20v2;manufacturer=SoftHSM%20project;serial=1738380edb324b07;token=demo
        Label: demo
        Type: Generic token
        Flags: RNG, Requires login
        Manufacturer: SoftHSM project
        Model: SoftHSM v2
        Serial: 1738380edb324b07
        Module: /usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so

nginx :: ~ »

Creating keys in your new HSM

So, now you want to create one or more private + public key pairs to use with things like certificates.

nginx :: ~ » alias hsm='pkcs11-tool --module /usr/lib/softhsm/libsofthsm2.so --login --pin 123456 --token-label "demo"'
nginx :: ~ » hsm -k --key-type EC:prime256v1 -a root/ec256
Key pair generated:
Private Key Object; EC
  label:      root/ec256
  Usage:      decrypt, sign, unwrap, derive
Public Key Object; EC  EC_POINT 256 bits
  EC_POINT:   044104ff98cfd24b33053cb2cab892e4a4cc40f5135c9a63f2e75b5f97a63281f290602114a4e4cffec7fa36528924e11b877131515df2ccc8df520eebb4134b49fb3b
  EC_PARAMS:  06082a8648ce3d030107
  label:      root/ec256
  Usage:      encrypt, verify, wrap, derive
nginx :: ~ » hsm -k --key-type EC:secp384r1 -a root/ec384
Key pair generated:
Private Key Object; EC
  label:      root/ec384
  Usage:      decrypt, sign, unwrap, derive
Public Key Object; EC  EC_POINT 384 bits
  EC_POINT:   046104fc995bc330972a1f1f18543e936d7409f5e5fd30d304a48847a9d03994d2283424d13f4f56b8adec12b5629904a1611e53dcda930308a91ef845dbd1cd33b4eee28c360f7951ae4124debf154abdadeac99668fdd349b6a09551f736d564a29d
  EC_PARAMS:  06052b81040022
  label:      root/ec384
  Usage:      encrypt, verify, wrap, derive
nginx :: ~ » hsm -k --key-type RSA:4096 -a root/rsa4096
Key pair generated:
Private Key Object; RSA
  label:      root/rsa4096
  Usage:      decrypt, sign, unwrap
Public Key Object; RSA 4096 bits
  label:      root/rsa4096
  Usage:      encrypt, verify, wrap
nginx :: ~ » hsm -k --key-type RSA:2048 -a root/rsa2048
Key pair generated:
Private Key Object; RSA
  label:      root/rsa2048
  Usage:      decrypt, sign, unwrap
Public Key Object; RSA 2048 bits
  label:      root/rsa2048
  Usage:      encrypt, verify, wrap
nginx :: ~ » hsm -O
Private Key Object; EC
  label:      root/ec256
  Usage:      decrypt, sign, unwrap, derive
Public Key Object; RSA 2048 bits
  label:      root/rsa2048
  Usage:      encrypt, verify, wrap
Public Key Object; EC  EC_POINT 256 bits
  EC_POINT:   044104ff98cfd24b33053cb2cab892e4a4cc40f5135c9a63f2e75b5f97a63281f290602114a4e4cffec7fa36528924e11b877131515df2ccc8df520eebb4134b49fb3b
  EC_PARAMS:  06082a8648ce3d030107
  label:      root/ec256
  Usage:      encrypt, verify, wrap, derive
Private Key Object; EC
  label:      root/ec384
  Usage:      decrypt, sign, unwrap, derive
Private Key Object; RSA
  label:      root/rsa4096
  Usage:      decrypt, sign, unwrap
Public Key Object; RSA 4096 bits
  label:      root/rsa4096
  Usage:      encrypt, verify, wrap
Private Key Object; RSA
  label:      root/rsa2048
  Usage:      decrypt, sign, unwrap
Public Key Object; EC  EC_POINT 384 bits
  EC_POINT:   046104fc995bc330972a1f1f18543e936d7409f5e5fd30d304a48847a9d03994d2283424d13f4f56b8adec12b5629904a1611e53dcda930308a91ef845dbd1cd33b4eee28c360f7951ae4124debf154abdadeac99668fdd349b6a09551f736d564a29d
  EC_PARAMS:  06052b81040022
  label:      root/ec384
  Usage:      encrypt, verify, wrap, derive
nginx :: ~ »

Now, to use your new keys with other things like OpenSSL / GNU TLS, you often need the URL:

nginx :: ~ » p11tool --login --list-privkeys
warning: no token URL was provided for this operation; the available tokens are:

pkcs11:model=p11-kit-trust;manufacturer=PKCS%2311%20Kit;serial=1;token=System%20Trust
pkcs11:model=SoftHSM%20v2;manufacturer=SoftHSM%20project;serial=1738380edb324b07;token=demo
nginx :: ~ » p11tool --login --list-privkeys "pkcs11:model=SoftHSM%20v2;manufacturer=SoftHSM%20project;serial=1738380edb324b07;token=demo"
Token 'demo' with URL 'pkcs11:model=SoftHSM%20v2;manufacturer=SoftHSM%20project;serial=1738380edb324b07;token=demo' requires user PIN
Enter PIN:
Object 0:
        URL: pkcs11:model=SoftHSM%20v2;manufacturer=SoftHSM%20project;serial=1738380edb324b07;token=demo;object=root%2fec256;type=private
        Type: Private key (EC/ECDSA-SECP256R1)
        Label: root/ec256
        Flags: CKA_WRAP/UNWRAP; CKA_PRIVATE; CKA_NEVER_EXTRACTABLE; CKA_SENSITIVE;
        ID:

Object 1:
        URL: pkcs11:model=SoftHSM%20v2;manufacturer=SoftHSM%20project;serial=1738380edb324b07;token=demo;object=root%2fec384;type=private
        Type: Private key (EC/ECDSA-SECP384R1)
        Label: root/ec384
        Flags: CKA_WRAP/UNWRAP; CKA_PRIVATE; CKA_NEVER_EXTRACTABLE; CKA_SENSITIVE;
        ID:

Object 2:
        URL: pkcs11:model=SoftHSM%20v2;manufacturer=SoftHSM%20project;serial=1738380edb324b07;token=demo;object=root%2frsa4096;type=private
        Type: Private key (RSA-4096)
        Label: root/rsa4096
        Flags: CKA_WRAP/UNWRAP; CKA_PRIVATE; CKA_NEVER_EXTRACTABLE; CKA_SENSITIVE;
        ID:

Object 3:
        URL: pkcs11:model=SoftHSM%20v2;manufacturer=SoftHSM%20project;serial=1738380edb324b07;token=demo;object=root%2frsa2048;type=private
        Type: Private key (RSA-2048)
        Label: root/rsa2048
        Flags: CKA_WRAP/UNWRAP; CKA_PRIVATE; CKA_NEVER_EXTRACTABLE; CKA_SENSITIVE;
        ID:

nginx :: ~ »

For instance, to create a CSR for:

You would do the following:

openssl req -new -sha256 -out hsm.finalx.nl.csr \
    -engine  pkcs11 \
    -keyform engine \
    -key "pkcs11:model=SoftHSM%20v2;manufacturer=SoftHSM%20project;serial=1738380edb324b07;token=demo;object=root%2frsa4096;type=private" \
    -subj "/CN=hsm.finalx.nl" \
    -reqexts SAN \
    -config <(cat /etc/ssl/openssl.cnf \
        <(printf "\n[SAN]\nsubjectAltName=DNS:hsm.finalx.nl,DNS:*.hsm.finalx.nl,DNS:secure.finalx.nl,DNS:*.secure.finalx.nl"))

Which will ask for your User PIN and then write out the Certificate Request, which you can then submit to your CA (like Let's Encrypt) to be signed by them.

For instance, I let my Puppet machine handle all the validations for Let's Encrypt, so I submit it from there:

dehydrated -s hsm.finalx.nl.csr

Which will in turn give me a certificate and I can then save as hsm.finalx.nl.pem.

Using it with nginx