PKCS#11 Hardware Security Module

DS servers support key management using a PKCS#11 token store. The PKCS#11 standard defines a cryptographic token interface, a platform-independent API for storing keys in an HSM, for example.

DS servers use an HSM only to hold asymmetric key pairs and, optionally, CA certificates.

Since the CA certificate holds the CA’s public key, ForgeRock recommends storing it in a separate, file-based keystore or PEM file, not in the HSM.

The asymmetric key pairs include the server’s TLS keys, and the shared master key for the deployment.

DS servers use the shared master key to wrap symmetric (secret) keys. DS servers store secret keys in the data they encrypt. Therefore, DS servers do not use the HSM for secret keys.

You can store the master key, technically an asymmetric key pair, on the HSM as long as the HSM supports importing the master key. Generate the master key (pair) into a PKCS#12 keystore, or PEM file, and import the keys into the HSM.

If you store the shared master key in an HSM, the HSM must share the same master key with all DS servers in the deployment. Each server unwraps secret keys with the master key. Without access to the shared master key, DS servers cannot read each others' encrypted data.

Using a PKCS#11 device for storing DS keys involves:

  • Storing the keys on the PKCS#11 device.

    How you store keys in a device such as an HSM depends on the device. For details, see the documentation for your device.

  • Creating the DS PKCS11 key manager provider to access the device.

    The DS server accesses a PKCS#11 device using a PIN. The PIN can be provided in the server configuration, in a separate file, or as the value of an environment variable or Java system property. The PIN must be stored as a cleartext value, so take care to protect it in production environments.

  • Configuring other components to use the key manager provider.

    For example, DS connection handlers and OAuth 2.0 authorization mechanisms requiring mutual TLS can reference the key manager provider in their configurations.

The following procedures demonstrate how to use the SoftHSM PKCS#11 software device for evaluation, development, and testing:

Prepare the HSM Simulator

The procedures uses the sun.security.pkcs11.SunPKCS11 provider implementation with SoftHSM. If you use a different Java implementation, see the documentation for details on how to use PKCS#11 devices with your JVM:

  1. Install SoftHSM, including the configuration and the SOFTHSM2_CONF environment variable.

    For details, see the SoftHSM documentation, using the following hints:

    • Make sure you can write tokens to SoftHSM:

      $ cat $SOFTHSM2_CONF
      
      # SoftHSM v2 configuration file
      
      # You must be able to write to the token dir when initializing the device:
      directories.tokendir = /path/to/softhsm/tokens
      objectstore.backend = file
      
      # ERROR, WARNING, INFO, DEBUG
      log.level = INFO
    • Keep track of the PINs that you enter when initializing the device:

      $ softhsm2-util --init-token --slot 0 --label "My token 1"
      
      *** 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.

      The SO PIN is to reinitialize the token.

      The user PIN is the one the DS server needs to access the device.

  2. Generate a key pair on the device:

    • To use the Java keytool command with the device, create a PKCS#11 configuration file that is used by the security provider implementation:

      $ cat /path/to/softhsm/hsm.conf
      
      name = SoftHSM
      library = /path/to/softhsm/2.0.0/lib/softhsm/libsofthsm2.so
      slot = 0
      attributes(generate, *, *) = {
         CKA_TOKEN = true
      }
      attributes(generate, CKO_CERTIFICATE, *) = {
         CKA_PRIVATE = false
      }
      attributes(generate, CKO_PUBLIC_KEY, *) = {
         CKA_PRIVATE = false
      }
      attributes(*, CKO_SECRET_KEY, *) = {
         CKA_PRIVATE = false
      }

      Notes regarding the configuration file:

      • The format is described in the Java PKCS#11 Reference Guide.

      • The library must point to the SoftHSM libsofthsm2.so library.

      • The slot must be one used when initializing the device.

    • Using the configuration file, generate the key pair.

      The following example generates a key pair with the alias server-cert:

      $ keytool \
       -genkeypair \
       -alias server-cert \
       -keyalg EC \
       -keysize 2048 \
       -ext "san=dns:ds.example.com" \
       -dname "CN=ds.example.com,O=Example Corp,C=FR" \
       -keystore NONE \
       -storetype PKCS11 \
       -providerClass sun.security.pkcs11.SunPKCS11 \
       -providerArg /path/to/softhsm/hsm.conf
      
      Enter keystore password:

      The keystore password is the user PIN.

    • Self-sign the public key certificate:

      $ keytool \
       -selfcert \
       -alias server-cert \
       -keystore NONE \
       -storetype PKCS11 \
       -providerClass sun.security.pkcs11.SunPKCS11 \
       -providerArg /path/to/softhsm/hsm.conf
      
      Enter keystore password:

      The keystore password is the user PIN.

      Using a CA-signed cert is similar, but not shown here.

Create a PKCS#11 Key Manager Provider

  1. Make sure you have the plain text PIN.

    With SoftHSM, this is the user PIN set when initializing the slot where you stored the keys.

  2. Make sure that the Java environment can find SoftHSM with its configuration.

    For example, add a provider definition by using an extra Java security properties file as in the following example. In this example, 10 security providers are already defined in the system java.security file. The configuration must use the next available key, which is security.provider.11:

    # Define the additional security provider in the extra file:
    $ cat /path/to/opendj/config/java.security
    
    # Security provider for accessing SoftHSM:
    security.provider.11=sun.security.pkcs11.SunPKCS11 /path/to/softhsm/hsm.conf
    
    # Use the extra file when starting the DS server:
    $ grep java.security /path/to/opendj/config/java.properties
    
    start-ds.java-args=-server -Djava.security.properties=/path/to/opendj/config/java.security
    
    # Restart the DS server so the changes take effect:
    $ stop-ds --restart
  3. Create the PKCS#11 key manager provider configuration.

    The following example creates a provider for SoftHSM with a protected PIN file:

    $ touch /path/to/opendj/config/softhsm.pin
    
    $ chmod 600 /path/to/opendj/config/softhsm.pin
    
    $ vi /path/to/opendj/config/softhsm.pin
    
    # Add the user PIN on the first and only line in the file, and save your work.
    $ dsconfig \
     create-key-manager-provider \
     --hostname localhost \
     --port 4444 \
     --bindDN uid=admin \
     --bindPassword password \
     --provider-name SoftHSM \
     --type pkcs11 \
     --set enabled:true \
     --set key-store-pin:"&{file:/path/to/opendj/config/softhsm.pin}" \
     --usePkcs12TrustStore /path/to/opendj/config/keystore \
     --trustStorePassword:file /path/to/opendj/config/keystore.pin \
     --no-prompt

    DS key manager providers also support storing the PIN in the configuration, in an environment variable, or in a Java property.

Use the PKCS#11 Key Manager Provider

  1. Set a connection handler or authorization mechanism to use the PKCS#11 key manager provider.

    The following example configures the LDAPS connection handler to use the SoftHSM provider:

    $ dsconfig \
     set-connection-handler-prop \
     --hostname localhost \
     --port 4444 \
     --bindDN uid=admin \
     --bindPassword password \
     --handler-name LDAPS \
     --set listen-port:1636 \
     --set enabled:true \
     --set use-ssl:true \
     --set key-manager-provider:SoftHSM \
     --usePkcs12TrustStore /path/to/opendj/config/keystore \
     --trustStorePassword:file /path/to/opendj/config/keystore.pin \
     --no-prompt
  2. Verify that the secure connection negotiation works with the HSM configured:

    $ ldapsearch \
     --hostname ds.example.com \
     --port 1636 \
     --useSSL \
     --baseDN dc=example,dc=com \
     "(uid=bjensen)" \
     cn
    
    The server is using the following certificate:
        Subject DN:  CN=ds.example.com, O=Example Corp, C=FR
        Issuer DN:  CN=ds.example.com, O=Example Corp, C=FR
        Validity:  <validity-period>
    Do you wish to trust this certificate and continue connecting to the server?
    Please enter "yes" or "no": yes
    
    dn: uid=bjensen,ou=People,dc=example,dc=com
    cn: Barbara Jensen
    cn: Babs Jensen