Hardware Security Modules (HSM)

EJBCA has support for several Hardware Security Modules (HSMs) and each HSM has its own specific interface for key generation and maintenance, independent of EJBCA. Make sure you are familiar with how your HSM works.

The following provides information on Hardware Security Modules (HSMs) in the following sections.

HSM Modules Available in the CA UI

You can manage crypto tokens fully in the EJBCA CA UI or CLI. and the CA UI automatically displays the HSMs available in your system.

When creating a new Crypto Token (Crypto Tokens>Create New) you can select between Soft and PKCS#11 crypto tokens.

  • The PKCS#11 option is only available if EJBCA is able to find any known PKCS#11 modules in the file system.

If EJBCA finds known PKCS#11 modules in the file system, you can select PKCS#11 as Type. As PKCS#11 Library there is a list of the available known HSMs found in the file system.

If the PKCS#11 option is not available or your desired HSM is not in the list of available Libraries, there are a few options to configure:

  • If you are using JBoss 7 you must make the java PKCS#11 classes exportable. For more information, see Application Servers.

  • You can configure PKCS#11 modules that are not already known to EJBCA in conf/web.properties. See conf/web.properties.sample how to add new known modules and override existing (overriding should not be needed since you can add new locations with the same name).

For more information on creating and using Crypto Tokens for HSMs, see Managing Crypto Tokens and Managing CAs.

The following sections describe the underlying operations and technical features of using HSMs and PKCS#11.

Configuring HSMs

Please note that FIPS mode does not allow the same key to be used for signing and encryption.

The GUI configuration of CAs is backed by a properties field where properties unique to a particular CAs usage of the HSM is specified. All implemented HSM modules are using the same property keywords to define the identity and the purpose of the keys to be used. These keywords are:

  • certSignKey: Key used when signing certificates, can be RSA or ECDSA.

  • crlSignKey: Key used when signing CRLs, can be RSA or ECDSA.

  • keyEncryptKey: Key used for key encryption and decryption, this must be an RSA key.

  • testKey: Key used by HSM status checks, can be RSA or ECDSA.

  • hardTokenEncrypt: Key used for hardtoken encryption and decryption. PUK will be decrypted by this key.

  • defaultKey: Key used when no other key is defined for a purpose. If this is the only definition, then this key will be used for all purposes.

  • pin: Optional pin code used for auto-activation of a CA token, see below. Not recommended for high security set-ups, but very useful in some cases.

You may omit defaultKey if you want to be sure that the right key is used, but then all the other keys must be specified. It is recommended that the certificate and CRL signing keys are linked to the same key since different keys are rarely supported by verifying applications.

When implementing support for a new HSM the KeyStrings class could be used to manage the key properties described above. When it is an JCA/JCE API for the HSM it could also be wise to extend the BaseCAToken class.

The same activation code must be used for all keys used by a CA.

There are four additional key properties that can (optionally) be used when renewing CA keys and to produce roll-over certificates. Some of these (in particular the next keys) are only used when using API methods (such as WS).

  • previousCertSignKey : Alias of the previous signature key, as opposed to certSignKey which is the current signature key.

  • previousSequence: Sequence identifying the previous signature key, as opposed to the current sequence that is held in the CA token. This sequence will replace the current sequence in the caRef field when signing a request with the CAs previous key.

  • nextCertSigningKey: Alias of a new generated key on the HSM. When updating a CA signed by an external CA this is used to send a request, but the CA is still active using the old key. When the certificate response is received this key is activate and moved to certSignKey/crlSignKey.

  • nextSequence: Sequence identifying the next signature key.

Supported and tested HSMs are described below, with sample configurations and HSM specific documentation.

As of EJBCA 3.6, the recommended HSM connector to use the PKCS#11 interface. Older JCE implementations are deprecated and removed. Contact PrimeKey if you need to migrate.

Testing PKCS#11 keys for use by EJBCA

To test keys on the HSM for use by EJBCA, you can use the EJBCA Client Toolbox.

ant clientToolBox
cd dist/clientToolBox
./ejbcaClientToolBox.sh PKCS11HSMKeyTool test

The command gives further instructions about the parameters required, PKCS#11 library and slot.

Auto-activation of Crypto Tokens

The pin property is used to be able to automatically activate a CA token. The activation code may be specified in the property field with the keyword pin. If this property is not specified, then the CA has to be manually activated after each restart or re-deployment of EJBCA. Manual activation is done in the Admin GUI under Basic Functions > View Information or using the cli bin/ejbca.sh ca activateca.

The pin property can use a clear text password or an encrypted one.

pin foo123
pin 6bc841b2745e2c95e042a68b4777b34c

These two properties contain the same password. The obfuscated pin value can be obtained with the command bin/ejbca.sh encryptpwd:

$ bin/ejbca.sh encryptpwd foo123
Using JBoss JNDI provider...
Please note that this encryption does not provide absolute security, ....
Enter word to encrypt:
hidden
Encrypting pwd...
6bc841b2745e2c95e042a68b4777b34c

This encrypted password is not a high security encryption. If the password.encryption.key property has not been customized it will not provide more security than just preventing accidental viewing since an EJBCA built-in encryption key is used. If an attacker gets hold of the encrypted password and the password.encryption.key has not been customized, the password can be decrypted using the source code of EJBCA.

HSMs and DSA or ECDSA

Support for DSA or ECDSA in HSMs are dependent on the support for the algorithms in the HSM and you need to confirm whether support is available.

For more information on HSMs and ECDSA, see ECDSA Keys and Signatures.

Support for New HSMs

EJBCA uses PKCS#11 and can, in theory, support any HSMs that provide a decent PKCS#11 implementation. If the HSM is uncommon you may have to provide specific attribute parameters as described for an 'attributesFile', see Generic PKCS#11 Provider.

PKCS11 Spy

You can debug PKCS11 sessions and all calls made, using OpenSC's P11Spy. As of EJBCA 6.8.0, P11Spy is by default included in the known P11 implementation in con/web.properties.

Stop JBoss, install P11Spy, and set the environment variables used in the JBoss terminal:

apt-get install opensc-pkcs11
export PKCS11SPY=/usr/local/lib/softhsm/libsofthsm2.so
export PKCS11SPY_OUTPUT=logfile.log

Then start JBoss and create a new PKCS11 Crypto Token using the PKCS11Spy PKCS#11 Library.

Remote Forwarding PKCS#11 using P11-Kit

P11-kit can be used to forward for example a USB Token HSM connected to your local laptop to a server running EJBCA. This allows you have your HSM in your control, while running the server somewhere else, for example in the cloud. It requires some setup and some work when you disconnect/connect your token, but can work for low scale deployments.

The following is an outline of commands to get a NitroKey HSM (connected to Local) available to a remote server (Remote) over P11-kit. EJBCA runs on the remote server. This is based on information by Maxence Mohr on PKI and HSM in a SME and remote-hsm, and tested on Ubuntu 16.04 and 18.04.

Install p11-kit on both Remote and Local

sudo apt install gcc make gtk-doc-tools help2man texinfo texlive-base libffi-dev libtasn1-dev gnutls-bin
wget https://github.com/p11-glue/p11-kit/releases/download/0.23.15/p11-kit-0.23.15.tar.gz
tar zxvf p11-kit-0.23.15.tar.gz
cd p11-kit-0.23.15/
./configure
make
make check
sudo make install
ls -al /usr/local/bin/p11-kit
ls -al /usr/local/lib/pkcs11/p11-kit-client.so
 
mkdir -p ~/.config/systemd/user
vi ~/.config/systemd/user/p11-kit-client.service
-----
[Unit]
Description=p11-kit client
 
[Service]
Type=oneshot
RemainAfterExit=true
RuntimeDirectory=p11-kit
ExecStart=/bin/true
 
[Install]
WantedBy=default.target
-----
 
systemctl --user daemon-reload
systemctl --user enable p11-kit-client.service
systemctl --user start p11-kit-client.service
ls /run/user/`id -u`/

Use SSH to forward P11 from Local to Remote

Run SSH from the machine where you plug your USB device (local) towards the server where you run EJBCA (remote).

# see https://github.com/fladna9/remote-hsm/blob/master/remote-hsm.sh
 
# Verifying if systemd user service is enabled (local).
systemctl --user status p11-kit-client.service | grep "Active: active"
# If _not_ running, start it
systemctl --user enable p11-kit-client.service
systemctl --user start p11-kit-client.service
 
# Verifying if systemd user service is enabled (remote). On Local:
ssh user@192.168.122.1 systemctl --user status p11-kit-client.service | grep "Active: active"
# If _not_ running, start it
ssh user@192.168.122.1 systemctl --user enable p11-kit-client.service
ssh user@192.168.122.1 systemctl --user start p11-kit-client.service
 
# On Local (with the USB Token), get tokenURL and start p11-kit server
p11tool --provider /usr/lib/x86_64-linux-gnu/opensc-pkcs11.so --list-token-urls
(pkcs11:model=PKCS%2315%20emulated;manufacturer=www.CardContact.de;serial=DENK0101866;token=UserPIN%20%28SmartCard-HSM%29)
p11-kit server --provider /usr/lib/x86_64-linux-gnu/opensc-pkcs11.so pkcs11:model=PKCS%2315%20emulated;manufacturer=www.CardContact.de;serial=DENK0101866;token=UserPIN%20%28SmartCard-HSM%29
(P11_KIT_SERVER_ADDRESS=unix:path=/run/user/1000/p11-kit/pkcs11-389; export P11_KIT_SERVER_ADDRESS;P11_KIT_SERVER_PID=390; export P11_KIT_SERVER_PID;)
 
eval P11_KIT_SERVER_ADDRESS=unix:path=/run/user/1000/p11-kit/pkcs11-389; export P11_KIT_SERVER_ADDRESS;P11_KIT_SERVER_PID=390; export P11_KIT_SERVER_PID;
 
# Done, local socket is at ${P11_KIT_SERVER_ADDRESS}
 
# SSH tunneling the socket to remote EJBCA instance. On Local:
ssh user@192.168.122.1 systemd-path user-runtime
(/run/user/1000)
ssh -N -f -R /run/user/1000/p11-kit/pkcs11:${P11_KIT_SERVER_ADDRESS#*=} user@192.168.122.1
# SSH tunneling done, remote socket is at 192.168.122.1:/run/user/1000/p11-kit/pkcs11
 
# Test remote access to token, from Local
ssh user@192.168.122.1 pkcs11-tool --module /usr/local/lib/pkcs11/p11-kit-client.so -L

If things fail and you have to start over, you need to clean sockets:

# On Local:
rm /run/user/1000/p11-kit/*
pkill -f p11-kit-server
pkill -f p11-kit-remote
pkill -f "ssh -N -f -R /run/user/"
# On Local (to Remote)
DISTANTRUN=$(ssh user@192.168.122.1 systemd-path user-runtime)
ssh user@192.168.122.1 rm "$DISTANTRUN/p11-kit"/*

Using SHA256WithRSAandMGF1 (RSASSA-PSS)

You can create CAs, using HSMs that support it, with the SHA256WithRSAandMGF1 a.k.a SHA256WithRSASSA-PSS algorithm (and SHA384 and SHA512). The software in EJBCA supports it, but some versions of the Java PKCS#11 provider do not.

Support for RSASSA-PSS was implemented in OracleJDK 8u241, OpenJDK 8u272, and 11.0.6. In JDK 8 it only works with RSA keys larger than 4096 bits due to this bug (fixed in JDK 11 but not backported to JDK 8). The default support in Java PKCS#11 only works with EJBCA 7.4.3.2 and later.

Older versions of OpenJDK and OracleJDK does not have support for SHA256WithRSAandMGF1 (also known as RSASSA-PSS) in the PKCS#11 provider. PrimeKey has made a patch for these versions of the JDK. Enterprise users can get a compiled patch together with an installation script for Debian-based operating systems from PrimeKey. The patch should work together with HSMs that have support for SHA256WithRSAandMGF1.

Relevant issues in the EJBCA issue tracker are ECA-2014 and ECA-9679.

Extending Sun PKCS#11 to set CKA_MODIFIABLE=false

PrimeKey does not recommend using this module. It was created due to a past PKCS#11 vulnerability that has since been patched by HSM vendors.

The tool described below is not compatible with Java 11 and the following information is kept as a reference only.

In order to change the CKA_MODIFIABLE attribute of a private key to FALSE directly after it has been generated the Sun PKCS#11 implementation must be extended. This extension must be done by adding classes to Installed Extensions classpath. See https://docs.oracle.com/javase/tutorial/ext/basics/install.html.

This is achieved by:

  • building cesecore-p11.jar with the command 'ant -Dbuild.cesecore.p11.jar=true build'

  • putting the '$EJBCA_HOME/dist/ext/cesecore-p11.jar' in one of the directories that is defined by the 'java.ext.dirs' system property.

You can put the jar in '$JAVA_HOME/jre/lib/ext'. You may also change the property to include the directory of the jar. Here is an example:

JAVA_OPTS="-Djava.ext.dirs=/usr/lib/jvm/java-7-openjdk-amd64/jre/lib/ext:$EJBCA_HOME/dist/ext" $JBOSS_HOME/bin/standalone.sh

Ensure to keep '$JAVA_HOME/jre/lib/ext' in the classpath.

To enable the feature in EJBCA, set 'pkcs11.makeKeyUnmodifiableAfterGeneration=true' in $EJBCA_HOME/conf/cesecore.properties.

If you use '$EJBCA_HOME/dist/ejbcaClientToolBox.sh' you do not have to set the java.ext.dirs setting as the configuration is performed by the script.

Everything will work without this jar in the classpath, but if it is not in classpath, the CKA_MODIFIABLE will be TRUE for every key that is generated and a warning written to the log.

The reason to set CKA_MODIFIABLE to FALSE is that it should not be possible to set CKA_DERIVE to TRUE. If CKA_DERIVE is true it might be possible to extract the private key from some HSMs (CVE-2015-5464), although most vendors have now patched this by not allowing weak key derivation schemes.

The ability to set CKA_MODIFIABLE=true is HSM vendor dependent and using the above method to change CKA_MODIFIABLE to false may not give the desired behaviour and thorough testing is advised.

Certain HSMs (for example SoftHSM2) refuses to set CKA_MODIFIABLE to FALSE (the PKCS#11 standard says that this behavior is OK).

In summary, the configuration requires careful testing. Tests can be performed using the clientToolBox tool with a generate-test cycle:

$EJBCA_HOME/dist/ejbcaClientToolBox.sh PKCS11HSMKeyTool generate (to generate a new key)
$EJBCA_HOME/dist/ejbcaClientToolBox.sh PKCS11HSMKeyTool test (to test, in a new PKCS#11 session if it is usable)

If you also generate keys using the Admin GUI, this should also be tested, together with restarting JBoss between generation and usage.