Cryptography

This chapter contains information how to manage the crypto configuration of the Identity Server.

Configuring certificates

To add new certificates to the crypto configuration, you can have the admin node of the server have certificate files read from etc/init upon server startup. The accepted files are PEM- or DER-encoded X509-certificates, that are named with the appropriate file extension (i.e. .pem, .der, .cer or .crt). As certificates are always used with a particular purpose, an ordering is applied based on the directory that contains the particular certificate file. When a certificate is imported, the filename (without the extension) is used as its id.

The following directory structure is used:

directory certificate purpose
etc/init/crypto/ssl-server-truststore a trusted server certificate used when setting up SSL/TLS connections. Imported in /facilities/crypto/ssl/server-truststore
etc/init/crypto/signature-verification a certificate that can can be used to verify a digital signature. Imported in /facilities/crypto/signature-verification-keys
etc/init/crypto/signer-truststores an issuer certificate that can be used to verify a digital signature from an upstream authentication provider. Imported in /facilities/crypto/signer-truststores

Example:

The X509-certificate stored as etc/init/crypto/ssl-server-truststore/www.example.com.der is imported in /facilities/crypto/ssl/server-truststore with an id www.example.com.

Note

This mechanism only allows adding new or replacing existing certificates in the configuration. To delete a certificate from configuration, please see Server Configuration overview.

Important

The server needs to be started with the appropriate start-up arguments to consider reloading configuration files, please for more information please see Server Configuration overview.

Configuring private keystores

As opposed to adding new certificates to the configuration, adding a keystore with a private key involves other actions than adding a certificate with just a public key, as a private key is usually transported with some layer of protection. There are two approaches for adding a new keystore to the configuration. The first method interacts with the configuration service, that validates and adds a given keystore into a running configuration. The other method is for preparing a keystore to be used in an XML-snippet that can be loaded by the server when it is configuring.

Both methods rely on starting with a private key that is stored in a base64-encoded PKCS12 or JKS file format.

Note

You can use tools like openssl to convert between existing keystore formats, or to create new key pairs. If you need to create a new RSA key pair, for example, you can use the following commands to create a new PKCS12 keystore with a 2048 bits RSA key pair, that is base64-encoded:

$ openssl req -x509 -sha256 -newkey rsa:2048 -keyout curity.key -out curity.crt -days 365
$ openssl pkcs12 -export -name curity -in curity.crt -inkey curity.key -out curity.p12
$ openssl base64 -in curity.p12 -out curity.p12-b64

Using an action to add a keystore

A keystore can be added through both the REST API of the configuration service, as well as by interacting with the CLI.

Using the REST API

Please have at hand the username and password for connecting to the configuration service (the defaults for username and password is set during installation).

When calling the REST API, you need a JSON document that defines the data that should be processed. This JSON document will look like this:

Listing 26 JSON document for adding a new keystore to the configuration
    {
        "input" : {
            "id" : "new-signing-key-alias",
            "password" : "Password1",
            "keystore" : "MIILAAIBAzCCCsYGCSqGSIb3DQEHAaCCCrcEggqzMIIKrzCCBUcGCSqGSIb3DQEH
    BqCCBTgwggU0AgEAMIIFLQYJKoZIhvcNAQcBMBwGCiqGSIb3DQEMAQYwDgQIOp3x
    I2T14A0CAggAgIIFANUdzBiORWjAdp9fJoT6MbVWRGPF0ZpfzIsCbvE+Lvw9/WE7
    ....
    BBRLDyRBzhw028jlcXJ2YcqA7KxkOQQIsHfJOFKfsQECAggA"
        }
    }

In the above document, replace the MIILAAI.... part with the contents of the base64-encoded keystore. Also, replace the id value with the name that should be assigned to the key in the configuration, and replace password with the password that you used to protect the pkcs12 keystore. Let’s save this file as add-signing-key.json so we can refer to this.

If you used the commands in the previous section to create a new keypair, the keystore contents are in the file curity.p12-b64 file that was created as result of base64-encoding the new keystore.

Now the following curl command will load the keystore in the configuration:

Listing 27 Use curl to add a new keystore to the configuration
$ KEYSTORE_OPERATION=add-signing-key-keystore
$ curl -k -X POST -u "admin:Password1" -H "Content-Type: application/vnd.yang.operation+json" \
    -d @add-signing-key.json \
    https://localhost:6749/admin/api/rest/running/facilities/crypto/_operations/$KEYSTORE_OPERATION

The server will confirm that the key was added, by responding with:

{
  "output": {
    "status": true
  }
}

Note the KEYSTORE_OPERATION variable. There are different operations for adding different keystores. The available operations are listed in the following table.

operation description
add-signing-key-keystore Adds a keystore to the signing keystores configuration
add-ssl-server-keystore Adds a keystore to the SSL server keystores configuration
add-ssl-client-keystore Adds a keystore to the SSL client keystores configuration
add-encryption-key-keystore Adds a keystore to the encryption keystores configuration
add-decryption-key-keystore Adds a keystore to the decryption keystores configuration
add-signature-verification-key Adds a a keystore to the signature verification keystores configuration
add-ssl-server-truststore Adds a certificate to the trusted SSL server certificates configuration
add-ssl-client-truststore Adds a certificate to the trusted SSL client certificates configuration
add-signer-truststore Adds a keystore to the signer truststores configuration

Using the CLI

Before getting into the CLI, prepare the base64-encoded file with the keystore to eliminate chunked lines and make it a one-liner. You can do that using the tr command line tool to do this:

$ tr -d '\n' < curity.p12-b64

The output is something you want to copy into your clipboard for use in the CLI.

Next, get in to the CLI . Once you have connected, enter the following command to add the new signing key:

request facilities crypto add-signing-key-keystore id new-signing-key-alias

Replace new-signing-key-alias with the desired id of the new keystore.

The CLI will ask for a value for keystore; here you should paste the contents of the base64-encoded keystore (e.g. the contents of the curity.p12-b64 file). Also enter the password that protects the PKCS12 keystore. The interaction should look something like this:

admin@my-host% request facilities crypto add-signing-key-keystore id new-signing-key-alias-from-cli
Value for 'keystore' (<string, min: 1 chars>): MIILAAIBAzCCCsYGCSqGSIb3DQEHAaC....qA7KxkOQQIsHfJOFKfsQECAggA
Value for 'password' (<string, min: 1 chars>): Password1
status true

(keystore contents abbreviated for readability).

Please look at the table at the end of the previous section for an overview of all different keystore types that can be added.

Preparing the keystore for embedding in an XML configuration document

In case you are preparing an XML configuration file, you can use the conversion tools to process a PKCS12 keystore into the data that can be used to configure the crypto facilities of the Curity Identity Server. See the section on Converting KeyStores (keystore-entry) into correct PKCS12 format.

The output of the conversion, a base64-encoded string, can be used in an XML-snippet:

Listing 28 Sample signing key configuration configuration
<config xmlns="http://tail-f.com/ns/config/1.0">
    <facilities xmlns="https://curity.se/ns/conf/base">
        <crypto>
            <signing-keys>
                <signing-key>
                    <id>default-signing-key</id>
                    <keystore>MIILAAIBAzCCCsYGCSqGSIb3DQEHAaC....qA7KxkOQQIsHfJOFKfsQECAggA</keystore>
                </signing-key>
            </signing-keys>
        </crypto>
    </facilities>
</config>

(keystore contents abbreviated for readability).

This XML can be added to the configuration in $IDSVR_HOME/etc/init and reloaded using the normal procedure.

Converting KeyStores (keystore-entry) into correct PKCS12 format

In Curity, private keys are stored in a pre-defined format in the configuration. To facilitate the conversion to this format, a convertks script is available in the bin directory of the Identity Server distribution.

The resulting key can be configured in the crypto-section as ssl/server-keystore, ssl/client-keystore, signing-keys, encryption-keys and decryption-keys.

Usage of the convertks script

The convertks script helps with processing a base64-encoded keystore, pick one Private Key entry out of that keystore, and write it as sole Entry in a new KeyStore. The output of the script is a base64-encoded version of this KeyStore.

There are two main ways of using the script, either by providing the input keystore as argument, or by providing it as a file.

The convertks script can show all its options when you invoke it with:

$ convertks --help

Provide KeyStore through command-line

Given a base64-encoded KeyStore (i.e. “MIInputKeystore”) that is protected with a KeyStore-password ‘KeyStorePassword’, containing an entry with an alias of ‘InputEntryAlias’ that is protected with password ‘InputEntryPassword’, the convertks script can be invoked with the following commandline:

$ convertks --in-password KeyStorePassword --in-alias InputEntryAlias --in-entry-password InputEntryPassword --in-keystore MIInputKeystore

Note: if entry-password is the same as password of the keystore, it can be omitted in the argument list.

This will output the KeyStore in the correct format to the console. If the output needs to be written to a file instead, add the --out-file parameter with the appropriate filename. The script will be silent.

Note that if any required argument is not provided, the script will prompt for it.

Using stdin

Instead of providing the keystore on the commandline itself, it can also be provided through stdin, i.e. with a command like:

$ cat "MIInputKeystore" | convertks --in-password KeyStorePassword --in-alias InputEntryAlias --in-entry-password InputEntryPassword

Provide KeyStore through file

If the base64-encoded KeyStore is stored in a file, this procedure is the same as above, but the --in-keystore parameter that provides the KeyStore must be replaced with the --in-file argument that contains the name of the file. Given that the file is “current-keystore-base64.txt”, the convertks script can be invoked with the following commandline:

$ convertks --in-password KeyStorePassword --in-alias InputEntryAlias --in-entry-password InputEntryPassword --in-file current-keystore-base64.txt --out-file new-keystore-base64.txt

Note: if entry-password is the same as password of the keystore, it can be omitted in the argument list.

This will output the KeyStore in the correct format to the file new-keystore-base64.txt

If there is no --out-file argument provided, the new keystore will be shown in the console.

Hardware Security Module

This section describes the setup of a Hardware Security Module (HSM) in the Curity Identity Server. Curity interfaces with an HSM using PKCS#11. This means that some kind of shared library is needed which provides this PKCS#11 capability. This is typically provided by the manufacturer of the HSM. Once an HSM is configured, keys can be used from the HSM. It is not required that all keys, public or private, reside on the HSM. It is possible to configure Curity to use some keys from its own configuration and others from the HSM. This can be especially helpful during testing, but can be useful even in production when it is desirable to configure the public keys in Curity rather than fetch them from the HSM (which may only be accessible over a network connection).

SSL, signature verification keys (public keys), signing keys, trust anchors, and client keys can all be configured to be stored on the HSM. When configuring a keystore, the admin just needs to specify that the key is located on the HSM. The admin node need not have access to the HSM; only run-time nodes that will use the keys housed in the HSM need access to the unit. This may be a subset of the run-time nodes depending on your deployment. There is currently no way to test the connectivity of the HSM from the admin node because it is assumed that this node won’t have access to an HSM.

In order for a key to be accessible to Curity, the HSM must contain not only a public key but also a certificate; without this, the key will not be found at run-time by Curity. The certificate can be self-signed, but it may also be signed by a trusted authority. The only algorithm supported at this time is RSA; elliptic curve and DSA keys cannot be used.

Entering a PIN

In order for each Curity run-time node to access keys on an HSM, they will need to login. This is done using a PIN or pass phrase. There are four ways to provide this PIN to Curity:

  1. On the command line using the -i flag with the PIN as an argument (e.g., idsvr -i 11223344)
  2. On the command line using the -i flag with a file as an argument where that file contains the PIN (e.g., idsvr -i ~/.hsm-pin)
  3. On the command line using only the -i flag and entering the PIN when prompted
  4. Using the environment variable IDSVR_HSM_PIN.

If the -i flag is used with a PIN as an argument (as in the first or second option above), then the admin will not need to interactively provide one. When provided directly on the command line, the PIN will be included in the output of ps and other such tools; to avoid this, the second option of reading the PIN from a file can be used. With this option, the file can be a symlink or pipe as well. The third option of providing the PIN through an environment variable may also make it accessible to such tools. If the PIN is set interactively, it will only be resident in the node’s memory and not accessible from outside tools (like ps). This method requires interactive input from an admin on the console during startup, however.

Configuring the HSM

Before any keystore can be configured as one residing in the HSM, the configuration for the unit must be defined. This is done by setting at least the path to the shared library that provides PKCS#11 support. This can be done using any of the management interfaces. For detailed information on the HSM-related settings, refer to the configuration reference.

Configuring the HSM in the GUI

To configure an HSM using the admin UI, navigate to the System ‣ General page. On this page, there is a section labeled Hardware Security Module. By default, this is toggled off, as shown in Fig. 41:

../../_images/hsm-disabled.png

Fig. 41 The HSM is toggled off (i.e., disabled) by default

Once it is toggled on, various settings can be configured. As shown in Fig. 42, the two that are required are some sort of identifier or name and the path (as it will be on any run-time node that uses the HSM) to the shared library that provides the PKCS#11 implementation.

../../_images/hsm-enabled.png

Fig. 42 The HSM can be toggled on and then the required settings and some optional ones can be configured

Either the slot list index or slot ID must be configured as well. By default, the list index is selected with a value of 0, but this can be changed as needed. The values will depend on the PKCS#11 provider used with the HSM. For example, to get this information with OpenSC, the pkcs11-tool command can be used as shown in Listing 29:

Listing 29 Getting information about the slots to use with OpenSC’s pkcs11-tool
$ pkcs11-tool -I
Cryptoki version 2.20
Manufacturer     OpenSC Project
Library          OpenSC smartcard framework (ver 0.17)
Using slot 0 with a present token (0x0)

To make the HSM as compatible with Curity as possible, the Include Compatibility Attributes option should be toggled on. If this poses a problem, select attributes can be enabled using the Mechanisms option. This option allows certain PKCS#11 mechanics to be enabled or disabled as needed. Valid mechanisms can be found in the PKCS#11 reference guide; any unrecognized value will cause the unit to be inaccessible and a warning to be logged.

Configuring the HSM in the CLI

The CLI can also be used to configure the HSM. For example, enter configuration mode and set it as shown in Listing 30:

Listing 30 Typical example of configuring an HSM using the CLI
admin@prod-curity1% set facilities crypto hardware-security-module library /usr/local/lib/opensc-pkcs11.so

To delete the HSM configuration, just issue the command delete facilities crypto hardware-security-module and commit the change.

Configuring the HSM in the REST API

The same CLI command in Listing 30 can be done with the REST API as shown in the following listing:

Listing 31 Typical example of configuring an HSM using the REST API
$ curl -k \
    -X PUT \
    https://localhost:6749/admin/api/rest/running/facilities/crypto/hardware-security-module \
    -u admin:Password1 \
    -H 'content-type: application/vnd.yang.data+xml' \
    -d '<hardware-security-module xmlns="https://curity.se/ns/conf/base">
            <library>/usr/local/lib/opensc-pkcs11.so</library>
            <disabled-pkcs11-mechanisms>CKM_ECDSA</disabled-pkcs11-mechanisms>
            <include-compatibility-attributes>true</include-compatibility-attributes>
        </hardware-security-module>'

Note that you have to do a PUT; a POST won’t work in this case even if the HSM isn’t yet configured.

To get the current configuration for the HSM using the REST API, a request like the one shown in Listing 32 can be used:

Listing 32 Example of getting or fetching the current configuration for the HSM
$ curl -k -u admin:Password1 \
  'https://localhost:6749/admin/api/rest/running/facilities/crypto/hardware-security-module?deep&with-defaults'

To delete an HSM from configuring using the REST API, a delete operation can be made like the one shown in Listing 33:

Listing 33 Deleting an HSM using the REST API
$ curl -k -X DELETE -u admin:Password1 https://localhost:6749/admin/api/rest/running/facilities/crypto/hardware-security-module

Debugging the PKCS#11 Provider

To get more information from the underlying PKCS#11 provider, you can pass the --debug-hsm flag to the idsvr command. This will cause all PKCS#11 keystore-related and provider-based messages to be written to the server log. You can also specify -Djava.security.debug=sunpkcs11,pkcs11keystore,pkcs11 in the JVM options of a certain node. If this method is used, the extra provider-related debugging information will be output after the node is restarted. When using this tactic, it can be helpful to include provider in the comma-separated list of debug message sources together with sunpkcs11, pkcs11keystore, and pkcs11. To set these and provider via the command-line, do not use the the --debug-hsm parameter; instead, pass it via the JAVA_OPTS environment variable when starting the idsvr command (e.g., JAVA_OPTS=-Djava.security.debug=sunpkcs11,pkcs11keystore,pkcs11,provider idsvr).

Some HSM providers, like OpenSC, include a proxy library that logs all access to the PKCS#11 module. To use such an interceptor, configure the proxy library as the one that Curity should use. In the case of OpenSC, in particular, the library that is being proxied needs to be set via an environment variable. This can be done from the shell when starting the idsvr command (e.g., PKCS11SPY=/usr/local/lib/opensc-pkcs11.so idsvr). In the same way, other environment variables of OpenSC’s can be set before invoking idsvr; for instance, the environment variable, OPENSC_DEBUG, can be set to some debug level, like 9, which results in trace-level debug messages being printed to the server log.