Developer's Guide
 All Files Variables Pages
KMIP Server Gateway (KSG)

Introduction

The KSG is a special purpose KMIP Server application that sits in front of existing HSMs (Hardware Security Modules). It provides an OASIS KMIP protocol interface to existing HSMs by translating KMIP protocol requests into PKCS#11 calls and then translating the PKCS#11 responses back into KMIP. The possible KMIP operations that are supported via KSG depend upon the limitations of the backend HSMs. KSG supports most commercially available HSMs. KSG also supports a local PKCS#11 software token.

Supported KMIP

KSG supports KMIP versions 1.0, 1.1, 1.2, 1.3, 1.4, 2.0 and 2.1. KSG supports all KMIP message formats: TTLV, TTLV over HTTPS, JSON, and XML. KSG is however limited in what KMIP operations it can support due to limitations enforced by the backend HSM in use (e.g., if the HSM is in FIPS mode many restrictions exist on its use). Currently, the following KMIP operations are supported:

* Activate
* Add Attribute
* Delete Attribute
* Destroy
* Discover Versions
* Create (both Symmetric Key and Secret Data Object)
* Create Key Pair
* Get (Symmetric Key, Public Key, Certificate, Secret Data)
* Get Attributes
* Get Attribute List
* Get Usage Allocation
* Locate
* Modify Attribute
* Obtain Lease
* Query
* Register
* Re-Key
* RNG Retrieve
* RNG Seed
* Revoke
* Decrypt
* Encrypt
* Sign
* Signature Verify
* MAC
* MAC Verify
* Derive Key (only HASH derivation method for SHA-2 keys are currently supported)
* Interop (for KMIP 2.0 and greater when enabled)
*
*

The following KMIP object types are supported: Symmetric Key, Secret Data, Public Key, Private Key, and Certificate.

The following limitations exist:

* 1) KMIP Get operaion for a Symmetric Key works on AWS CloudHSM and Cavium HSMs because both support a customer
* supplied Key Encrypting Key (KEK), which allows KSG to extract the Symmetric Key in wrapped form from the
* HSM and then locally decrypt it.
*
* 2) KMIP RNG Seed operation works if the HSM supports it.
* 3) Currently, a Secret Data Object created on a call to the KMIP Create operation is saved in the KSG database.
* In the future, a configuration item will allow this object to be saved on an HSM as a CKO_DATA object if the
* HSM supports CKO_DATA objects.
*
* 4) The KMIP Digest attribute can only be calculated if the backend HSM supports the PKCS#11 C_DigestKey() API call.
*
* 5) KMIP Encrypt, Decrypt, Sign, Signature Verify, MAC and MAC Verify operations are the non-streaming versions
* (as introduced in KMIP 1.2).
*
* 6) KMIP Register only allows a Certificate object to be loaded into the backend HSM.
*
* 7) Using the KMIP "Batch Error Continuation Option" set to "Undo" will not work properly with a KMIP "Destroy"
* operation. KSG's current undo implementation uses a database transaction of the KSG internal database to
* rollback the effect of operations in a failed KMIP request. However, when KSG is connected to an HSM this
* transaction does not include the HSM's state. So if a KMIP Destroy operation is performed, thus removing
* key material from the HSM, the current undo implementation will not restore the deleted key material.
* Thus KMIP Destroy operations are not supported in failed KMIP requests with an "Undo" error continuation.
*

KSG can run with the P6R PKCS#11 software token that does not run in FIPS mode. In this configuration, many of the limitations above do not exist, however, no HSM is in use.

KSG Setup

For this version of KSG the user must configure KSG's PKCS#11 module to talk to the user's HSM. In addition, the user must set up a TLS proxy to take incoming TLS requests and forward them to KSG (e.g., Stunnel) [in a future release KSG will have its own TLS server protocol handling as an option]. Here are the KSG set up steps.

* 1) Install KSG in the directory you will run it out of
* 2) Run the p6pkcs11tool to configure the P6R PKCS#11 module so it can talk to your HSM. (See documentation for the p6pkcs11tool that comes with KSG.)
* When PKCS#11 is properly configured the following files should appear in the ..<install directory>/data directory: PKCS11, PKCS11.sig, and pkcs11baseKey.txt
* Now KSG is ready to talk to your HSM.
* 3) Modify the ..<install directory>/confs/ksg.conf file (see options below under the section "Gateway Configuration Parameters").
* 4) Copy the P6R license file into the ..<install directory>/licenses/ directory.
* 5) Install and configure Stunnel (or another TLS proxy) to sit in front of KSG (see the section "KSG and Stunnel" below).
*

Note, to run the p6pkcs11tool on Linux currently requires setting LD_LIBRARY_PATH the to "<installed path>../components" directory so it can dynamically load libp6pkcs11.so, which is P6R's PKCS#11 library implementation. Otherwise, an error that the shared library cannot be found will be returned.

Note, that if you are upgrading your version of KSG please check the section "Are you running an older version of KSG?" below.

KSG and Stunnel

The first version of KSG relies on Stunnel (https://www.stunnel.org/) as its front end TLS proxy. (An equivalent TLS proxy can also be used.) Future versions of KSG will implement its own TLS server protocol. Of course, a customer can choose to use a different TLS proxy in front of KSG, but Stunnel is what has been used during testing.

To use Stunnel the customer needs access to a local CA in order to create the required server and client side authentication certificates required by the KMIP's use of the TLS protocol. During testing P6R has used OpenSSL to provide this set of features. Thus all TLS interactions between a KMIP client and KSG will be handled by Stunnel. Stunnel simply forwards the unencrypted KMIP requests to the KSG process.

For example, below is the contents of a stunnel.conf file that has been used in integration testing.

* ; stunnel SERVER
* client = no
* ; Log level: info = 6, debug = 7
* debug = 7
*
* pid = /var/run/stunnel.pid
* output = stunnel.log
*
* ; This enables mutual authentication, client needs a cert as well
* verify = 2
*
* ; set up a local CA
* cert = /etc/stunnel/server.pem
* key = /etc/stunnel/server_privkey.key
* CRLfile = /etc/stunnel/crl.pem
* CAfile = /etc/stunnel/cacert.pem
* ; We're in a chroot jail
* CApath = /CA
*
* ; Disable support for insecure SSLv2 protocol
* options = NO_SSLv2
*
* ; These options provide additional security at some performance degradation
* ; options = SINGLE_ECDH_USE
* options = SINGLE_DH_USE
*
* ; Force ciphers with Forward Secrecy / Perfect Forward Secrecy
* ciphers = DHE-RSA-AES256-SHA:DHE-DSS-AES256-SHA:AES256-SHA:KRB5-DES-CBC3-MD5:KRB5-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:EDH-DSS-DES-CBC3-SHA:DES-CBC3-SHA:DES-CBC3-MD5:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA:AES128-SHA:RC2-CBC-MD5:KRB5-RC4-MD5:KRB5-RC4-SHA:RC4-SHA:RC4-MD5:RC4-MD5:KRB5-DES-CBC-MD5:KRB5-DES-CBC-SHA:EDH-RSA-DES-CBC-SHA:EDH-DSS-DES-CBC-SHA:DES-CBC-SHA:DES-CBC-MD5:EXP-KRB5-RC2-CBC-MD5:EXP-KRB5-DES-CBC-MD5:EXP-KRB5-RC2-CBC-SHA:EXP-KRB5-DES-CBC-SHA:EXP-EDH-RSA-DES-CBC-SHA:EXP-EDH-DSS-DES-CBC-SHA:EXP-DES-CBC-SHA:EXP-RC2-CBC-MD5:EXP-RC2-CBC-MD5:EXP-KRB5-RC4-MD5:EXP-KRB5-RC4-SHA:EXP-RC4-MD5:EXP-RC4-MD5
*
* ; Here we specify where to proxy the incoming KMIP request
* [kmip]
* accept = 0.0.0.0:65521
* connect = 127.0.0.1:65524
*

Gateway Configuration Parameters

* [p6ksg-gen]
* baseKeyPath="ksgbaseKey.txt"
* serverLogFlags=1036
* HSM_pin="12345678"
* HSM_slotid=0
* HSM_name="AWSCloudHSM"
* HSM_addr=123.10.3.45
* HSMType=1
* gateFlags=1
* AWSCloudHSM_KEKHandle=262155
* KEKKeyPath="aes256.key"
*

Other possible configuration parameters

* CaviumLiquidSec_KEKHandle
*

The above configuration is used to define a single HSM that sits behind a KSG instance and is defined in the ksg.conf file. In the example, above that HSM is an AWS CloudHSM.

The "baseKeyPath" configuration parameter (string value), is the symmetric key protecting the PKCS 11 keystore is to be written to after it is generated by the library. This parameter can be either a full path to the key file or just the name of the key file. If it is just a file name then it will be treated as relative to the directory the library runs out of. Essentially, this is the one key that is kept in the clear. Either this parameter OR the "customerKeyPath" parameter is defined. If both are defined, then the customerKeyPath parameter will be used.

The "customerKeyPath" configuration parameter (string value), is the symmetric key protecting the PKCS 11 keystore. The difference between this parameter and the "baseKeyPath" is that the baseKeyPath key is generated by this command line tool while the customerKeyPath key is provided by the customer. The customer must provide an AES 256 bit PEM encoded file.

The "HSM_name" configuration parameter (string value), is used to store meta data into the P6R keystore for any key or other managed object in an HSM. This provides a way to segregate object meta data.

The "HSM_slotid" configuration parameter (positive integer value), is the PKCS#11 slot number expected by the HSM in use in order to open a PKCS#11 session.

The "HSM_addr" configuration parameter (string value), is the network address to connect to a network attached HSM.

The "HSM_type", optional, configuration parameter (positive integer value), is used to distinguish different HSMs which may require slightly different client side behavior. The current allowed values for this parameter are: { 0x0001 AWS CloudHSM, 0x0002 Cavium LiquidSecurity HSM, 0x0004 Entrust nShield HSM (formerly nCipher) }. The default value for this parameter is zero which results in no special behavior.

The "gateFlags", optional, configuration parameter (positive integer value), is used as a bit mask to define specific Gateway wide behavior. The current allowed values for this parameter are:

* 0x0001 recover signature - when the signature on the KSG keystore fails allow us to open it anyway,
* 0x0002 use P6R's PKCS#11 software token instead of an HSM,
* 0x0004 disable KSG from calling PKCS#11 C_DigestKey() API function because configured HSM does not support it
* 0x0008 enable KMIP Interop function for KMIP 2.X, default is disabled resulting in an error from KSG
*

The default value for this parameter is zero which results in no special behavior.

The "AWSCloudHSM_KEKHandle", configuration parameter (positive integer value), is the HSM object handle for the application KEK AES 256 bit key that has been loaded into the CloudHSM in order to export CloudHSM generated keys. This application KEK is either provided by the customer or generated via OpenSSL command line as part of the KSG initialization process. This application KEK is loaded into the CloudHSM using the AWS "key_mgmt_util" program following the sequence defined below. Note, that AWS CloudHSM object handles stay valid across PKCS#11 sessions.

The "CaviumLiquidSec_KEKHandle", configuration parameter (positive integer value), is the HSM object handle for the application KEK AES 256 bit key that has been loaded into the Cavium LiquidSecurity HSM in order to export HSM generated keys. This application KEK is either provided by the customer or generated via OpenSSL command line as part of the KSG initialization process. This application KEK is loaded into the HSM using the Cavium "Cfm3Util" program following the sequence defined below. Note, that Cavium LiquidSecurity HSMobject handles stay valid across PKCS#11 sessions.

The "KEKKeyPath", configuration parameter (string value), is the full path to the customer's AES 256 bit KEK stored in binary format. Note if no path is given then the file is assumed to be in the KSG data directory.

The "serverLogFlags", optional, configuration parameter (bit mask), defines the format the server should log all incoming and outgoing messages. The default value for this parameter is zero which disables all KMIP message logging. The following values can be used to create a bit mask value for this parameter.

* P6KMIPFLG_NOFLAGS - no component preferences set
* P6KMIPFLG_TRACE_OFF - no tracing to file
* P6KMIPFLG_TRACE_BASIC - high level trace of KMIP actions
* P6KMIPFLG_TRACE_MSGS - log all incoming and outgoing messages in the format selected by including one of the following
* format flags (e.g., P6KMIPFLG_TRACE_FORMATXML)
* P6KMIPFLG_TRACE_FORMATJSON - used with P6KMIPFLG_TRACE_MSGS, all incoming and outgoing messages are logged in JSON format.
* P6KMIPFLG_TRACE_VERBOSE - extensive logging of all internal components, meant for P6R use
* P6KMIPFLG_TRACE_FORMATKMIPXML - used with P6KMIPFLG_TRACE_MSGS, all incoming and outgoing messages are logged in KMIP XML dialect.
* P6KMIPFLG_TRACE_HTTPHEADERS - used with P6KMIPFLG_TRACE_MSGS, when using HTTPS generate a separate message showing all HTTP headers put on the wire
* P6KMIPFLG_TRACE_FORMATTTLV - used with P6KMIPFLG_TRACE_MSGS, all incoming and outgoing messages are logged in hexidecimal format showing their TTLV
* structure.
*
* P6KMIPFLG_NOFLAGS = 0x00000000
* P6KMIPFLG_TRACE_OFF = 0x00000002
* P6KMIPFLAGS P6KMIPFLG_TRACE_BASIC = 0x00000004
* P6KMIPFLAGS P6KMIPFLG_TRACE_MSGS = 0x00000008
* P6KMIPFLG_TRACE_FORMATJSON = 0x00000020
* P6KMIPFLAGS P6KMIPFLG_TRACE_VERBOSE = 0x00000100
* P6KMIPFLG_TRACE_FORMATKMIPXML = 0x00000400
* P6KMIPFLG_TRACE_HTTPHEADERS = 0x00000800
* P6KMIPFLG_TRACE_FORMATTTLV = 0x00002000
*
* Examples:
* logging in XML:
* P6KMIPFLG_TRACE_BASIC | P6KMIPFLG_TRACE_MSGS | P6KMIPFLG_TRACE_FORMATKMIPXML
* logging in JSON:
* P6KMIPFLG_TRACE_BASIC | P6KMIPFLG_TRACE_MSGS | P6KMIPFLG_TRACE_FORMATJSON
* logging in binary with TTLV parsing:
* P6KMIPFLG_TRACE_BASIC | P6KMIPFLG_TRACE_MSGS | P6KMIPFLG_TRACE_FORMATTTLV
* logging in XML, if using HTTP then also produce HTTP headers in a separate file:
* P6KMIPFLG_TRACE_BASIC | P6KMIPFLG_TRACE_MSGS | P6KMIPFLG_TRACE_FORMATKMIPXML | P6KMIPFLG_TRACE_HTTPHEADERS
*

To future control logging from PKCS#11 you can edit the "install directory".en_us. For example one line in this file is:

* libraryTrace = "info",0,"P6R Cryptoki library %1$ (error: %2$, %6$) (extra1: %3$ %4$) (extra2: %5$)"
*

The above is the default setting for this logging data. The "info" field can also be changed to "error", "warn", or "debug". The number after "info" is the log level to print that log data and the value of 0 means verbose. So to turn this logging data off one could change the zero to a 3. Out of the box these setting are set to log all PKCS#11 data so the customer can view what is happening during integration testing. After this testing many of the "info" lines in the file p6pkcs11.en_us should have their log level increased.

KMIP Server Configuration Parameters

KSG has an internal, generic KMIP server process to receive incoming KMIP requests. This section describes how that server is configured. Basic server's configuration parameters (e.g., port to connect to) are defined in the p6kmipserver.conf file.

* [p6kmip-gen]
* logDir = "/var/log/kmip"
* errorStream = "kmipclient-errors.txt"
* . . . . .
*
* [p6kmip-server-gen]
* listenPort = 65524
* maxBufSize = 20000
* initialBufCount = 10
* growBufBy = 5
* threadCount = 15
* listenIPAddr = 0.0.0.0
* receiveTimeout=500
* sendTimeout=500
* acceptTimeout=10
* KMIPMaxVersion=1.4
* KMIPMinVersion=1.2
*
*

The "logDir" configuration parameter (string value), defines an existing, writable directory where the KMIP server can write log files. If this configuration parameter is missing then logging will be disabled. Note, that the KMIP server will create directories under this log directory.

* /var/log/kmip
* /var/log/kmip/127.0.0.1/server/kmip-1382423469125976-1321.xml
*
*

In the above example, the KMIP server creates a "server" directory currently under localhost. All incoming KMIP requests made by clients are logged into that directory. Note, that the log file names for the server have two number parts. The first is a timestamp and the second part to their file name (e.g., kmip-1398708919378906-14844.xml), where the value after the 2nd "-" is the thread identifer that worked on the request. Since the server is multi-threaded messages will be mixed and sorted by time. To find the matching response sent for a request look for the next message with the same thread identifier, since a single thread handles the entire incoming request.

The "errorStream" configuration parameter (string value), is the name of a file to be created in the log directory that includes any XML/JSON/JsonML parsing errors and warning.

The "listenPort" configuration parameter (positive numeric value), is the port that the KMIP server component should listen on for incoming Notify / Put operations. The default value is 65524. This value can also be passed into the p6IKMIPServer::initialize() call allowing multiple instances of the KMIP server running at the same time.

The "maxBufSize" configuration paramter (positive numeric value), is the size of each allocated server buffer. The default value is 40000 bytes if not defined in the p6kmipserver.conf file.

The "initialBufCount" configuration parameter (positive numeric value), is the number of buffers the server should allocate on start up. The default value is 10 if not defined in the p6kmipserver.conf file.

The "growBufBy" configuration parameter (positive numeric value), is the number of buffers the server will allocate at once time when additional buffers are required to handle incoming requests. The default value is 10 if not defined in the p6kmipserver.conf file.

The "threadCount" configuration parameter (positive numeric value), is the number of threads created whenever a p6IKMIPServer component is created to process incoming Notify and Put requests. The default value is 10 if not defined in the p6kmipserver.conf file.

The "listenIPAddr" configuration parameter (string value), allows the KMIP server to support multi-homed machines. The default value is "0.0.0.0" if not defined in the p6kmipserver.conf file.

The "receiveTimeout" configuration parameter (positive numeric value), is the number of seconds that the KMIP server component will wait to receive incoming bytes from a connected socket. That is, how long it will wait to receive the next KMIP request from a client over an existing connection. If the timeout is exceeded, then the server will close down the TCP connection (which will cause the TLS session to also close). The default value is 300 (5 minutes) if not defined in the p6kmipserver.conf file.

The "sendTimeout" configuration parameter (positive numeric value), is the number of seconds that the KMIP server component will wait to send outgoing bytes over a connected socket. That is, how long it will wait to send a KMIP response message to a client over an existing connection. The default value is 300 (5 minutes) if not defined in the p6kmipserver.conf file.

The "acceptTimeout" configuration parameter (positive numeric value), is the number of seconds that the KMIP server component will wait to receive an incoming connection request. If the timeout is exceeded, a listener thread will wake up, log a warning, and then go back to waiting for the next incoming request. The default value is 10 if not defined in the p6kmipserver.conf file.

The "KMIPMaxVersion" configuration parameter (string value), allows the user to control the maximum KMIP protocol version that KSG should handle. Currently, this value defaults to "1.4" as KMIP 2.0 support is in development. Recognized string values are: { "1.0", "1.1", "1.2", "1.3", "1.4", "2.0" }.

The "KMIPMinVersion" configuration parameter (string value), allows the user to control the minimum KMIP protocol version that KSG should handle. Currently, this value defaults to "1.0". Recognized string values are: { "1.0", "1.1", "1.2", "1.3", "1.4", "2.0" }.

KSG Query Responses

A second configuration file: p6kmip_auxiliary_ksg.conf, has been added that defines the current capabilities of KSG. A customer can edit this file to remove capabilities that they wish to hide from KMIP clients during KMIP Query requests. For example, the values below are what is supported for the first release of KSG. These numbers come directly from the KMIP specification (e.g., operation "1" is Create).

* [p6kmip-server-auxiliary]
* vendorId = "www.p6r.com; KSG 2018.1"
* operations = 1,2,3,4,8,10,11,12,13,14,15,17,18,19,20,24,30,31,32,37,38
* objects = 1,2,3,4,7
* profiles =
*
* shreddingAlgorithm = 1
* destroyAction = 1
*

The "vendorId" configuration parameter (string value), is the string returned to a KMIP client performing a Query operation against P6R's KMIP server. In this case, the contents of the vendorId parameter is returned as part of a Query response when the "Query Server Information" flag is part of the Query request. This parameter is optional, nothing is returned for vendor information if vendorId parameter is not defined.

The "operations" configuration parameter, (a comma separated list of positive numeric values), defines all client side operations supported by the P6R client SDK. Operation values are defined in file p6kmip.h, Section 9.1.3.2.27 Operation Enumeration. The integer values in the list are the integer values defined for each enumeration.

The "objects" configuration parameter, (a comma separated list of positive numeric values), defines all objects types supported by the P6R client SDK. Object values are define in file p6kmip.h, Section 9.1.3.2.12 Object Type Enumeration. The integer values in the list are the integer values defined for each enumeration.

The "profiles" configuration parameter, (a comma separated list of positive numeric values), defines all the client profiles supported by the P6R client SDK. Profile values are defined in file p6kmipprofiles.h, Section 9.1.3.2.42 Profile Name Enumeration. The integer values in the list are the integer values defined for each enumeration. Note, that Suite B profiles depending on the customer using an OpenSSL library with the proper (EC) key support (profiles: 49,50,51,55,56,57).

The "shreadingAlgorithm" configuration parameter, (positive numeric value) defines the shreadding algorithm used by the client when destroying a key. Shreading algorithms are defined in file p6kmip.h, Section 9.1.3.2.45 Shredding Algorithm Enumeration. If not defined here the value defaults to KMIP_SHREDALG_UNSPECIFIED (1) (which is what most likely the value should be returned as).

The "destroyAction" configuration parameter, (positive numeric value) defines the the destroy action used by the client when destroying a key. Destroy action enumeration is defined in the file p6kmip.h, Section 9.1.3.2.44 Destroy Action Enumeration. If not defined here the value defaults to KMIP_ONDESTROY_UNSPECIFIED (1) (which is what most likely the value should be returned as).

The "unrapMode" configuration parameter, (positive numeric value) defines how the client unraps a wrapped key. The unrap mode enumeration is defined in the file p6kmip.h, Section 9.1.3.2.43 Unwrap Mode Enumeration. If not defined here the value defaults to KMIP_UNWRAPMODE_UNSPECIFIED (1).

The "RNGMode" configuration parameter, (positive numeric value) defines how a random number generator is implemented by the client. The RNG mode enumeration is defined in the file p6kmip.h, Section 9.1.3.2.46 RNG Mode Enumeration. If not defined here the value defaults to KMIP_RNGMODE_UNSPECIFIED (1).

The "streamingEnabled" configuration parameter, ( a boolean value) defines whether or not the client supports streaming cryptographic operations. Note that the P6R client SDK does support this feature. If not defined here the value defaults to true.

AWS CloudHSM Integration Set Up

The AWS CloudHSM allows a PKCS#11 client to extract a symmetric key that was generated on the CloudHSM. This extraction takes place via the use of the PKCS#11 C_WrapKey() API call. The Key Encrypting Key (KEK) used to wrap the symmetric key in the call to C_WrapKey() can be loaded into the CloudHSM and thus is known by the client. The wrapping algorithm used is the AWS Key Wrap with PKCS#5 Padding.

The above is important because it allows a KMIP GET operation, for a symmetric key created on the CloudHSM, to return the symmetric key in the clear. This allows many existing KMIP applications that expect to perform encryption locally to work with the AWS CloudHSM.

To achieve this a customer creates their own AES 256 bit key (as the known KEK) and stores that in a file in binary format (e.g., aes256.key). Then using AWS CloudHSM command line tools (to be shown below) the customer loads their KEK into the CloudHSM with a CKA_LABEL value that KSG will look for (i.e., "P6RKEK1"). Setting the CKA_LABEL as such allows KSG to locate the KEK later.

Once this setup is complete, then KSG will perform the AES Key Unwrap in its implementation of the KMIP GET operation for a symmetric key created on the CloudHSM. That is, KSG will first extract the symmetric key using PKCS#11 API call C_WrapKey() with the handle of the loaded customer KEK, and then call OpenSSL to perform the AES Unwrap function. The end result is that the symmetric key created on the CloudHSM is now in the clear to be returned to the requesting KMIP Client.

In the example below, please note that a key's handle returned by CloudHSM lasts across sessions of their command line tools and of PKCS#11 sessions. Also note that the handle value returned in step #2 is placed in the ksg.conf file as the "AWSCloudHSM_KEKHandle" parameter (see above).

The below sequence of command line operations loads the customer's KEK into the CloudHSM so it can be used to wrap a key during the PKCS#11 API call C_WrapKey(). Since KSG then knows this KEK it can locally unwrap the key. The sequence of /opt/cloudhsm/bin/key_mgmt_util command line tool calls are performed on the EC2 instance that AWS refers to as the "CloudHSM client instance" and is where KSG is installed.

Please refer to AWS documentation for a description of the commands used in the example below and what is necessary to use them.

* Pulling out the HSM generated key using a customer generated, permanent KEK key
* Assuming that the HSM generated key exists. It may be required to be logged into the HSM as a valid user
* during these operations such as "loginHSM -u CU -s <user> -p <pin>", where "<user>" and "<pin>" are replaced based on your
* HSM set up.
*
* 1> Generate a temporary session key to wrap our P6R (local) KEK
* /opt/cloudhsm/bin/key_mgmt_util genSymKey -l WrapperKey -t 31 -s 32 -sess
* This command provides a handle identifier to use later, lets call it "h1" (e.g., h1 can be "262155")
*
* 2> Load in the customer's KEK in a permenant key using 'h1'
* /opt/cloudhsm/bin/key_mgmt_util imSymKey -w 262155 -t 31 -f aes256.key -l P6RKEK1 (262155 is an example h1)
* The result of this command will also be to return the handle identifier of our loaded KEK, lets call it "h2" (e.g., h2 can be "262156")
*
* 3> Verify customer's KEK attributes
* /opt/cloudhsm/bin/key_mgmt_util getAttribute -o 262156 -a 512 -out keyinfo
* (Verify that CKA_WRAP and CKA_UNWRAP are set to OxO1, if not set then via setAttribute command line operation)
*
* 4> Optional, we can now export the application key using the customer's KEK, KSG will do this via PKCS#11
* /opt/cloudhsm/bin/key_mgmt_util exSymKey -w 262156 -k 262150 -out exported2
* "-w" is for the handle identifier of our loaded KEK (i.e., h2), while "-K" is the handle identifier of the key we want to export
*

Cavium LiquidSecurity HSM Set Up

The Cavium LiquidSecurity HSM allows a PKCS#11 client to extract a symmetric key that was generated on the HSM. This extraction takes place via the use of the PKCS#11 C_WrapKey() API call. The Key Encrypting Key (KEK) used to wrap the symmetric key in the call to C_WrapKey() can be loaded into the HSM and thus is known by the client. The wrapping algorithm used is the AWS Key Wrap with PKCS#5 Padding.

The above is important because it allows a KMIP GET operation, for a symmetric key created on the HSM, to return the symmetric key in the clear. This allows many existing KMIP applications that expect to perform encryption locally to work with the Cavium LiquidSecurity HSM.

To achieve this a customer creates their own AES 256 bit key (as the known KEK) and stores that in a file in binary format (e.g., aes256.key). Then using Cavium LiquidSecurity HSM command line tools (to be shown below) the customer loads their KEK into the HSM with a CKA_LABEL value that KSG will look for (i.e., "P6RKEK1"). Setting the CKA_LABEL as such allows KSG to locate the KEK later.

Once this setup is complete, then KSG will perform the AES Key Unwrap in its implementation of the KMIP GET operation for a symmetric key created on the HSM. That is, KSG will first extract the symmetric key using PKCS#11 API call C_WrapKey() with the handle of the loaded customer KEK, and then call OpenSSL to perform the AES Unwrap function. The end result is that the symmetric key created on the HSM is now in the clear to be returned to the requesting KMIP Client.

In the example below, please note that a key's handle returned by the HSM lasts across sessions of their command line tools and of PKCS#11 sessions. Also note that the handle value returned in step #2 is placed in the ksg.conf file as the "CaviumLiquidSec_KEKHandle" parameter (see above).

The below sequence of command line operations loads the customer's KEK into the HSM so it can be used to wrap a key during the PKCS#11 API call C_WrapKey(). Since KSG then knows this KEK it can locally unwrap the key. The sequence of /home/liquidsec_bin/bin/Cfm3Util command line tool calls are performed on a computer where KSG is installed.

Please refer to Cavium documentation for a description of the commands used in the example below and what is necessary to use them.

* Pulling out the HSM generated key using a customer generated, permanent KEK key
* Assuming that the HSM generated key exists.
*
* 1> Login into the HSM
* /home/liquidsec_bin/bin/Cfm3Util loginHSM -u CU -s <user> -p <pin>
* where "<user>" and "<pin>" are dependent on your setup (e.g., "-s crypto_user -p user123")
*
* 2> Generate a temporary session key to wrap our P6R (local) KEK
* Command: genSymKey -l WrapperKey -t 31 -s 32 -sess
* "Command:" is a prompt, this command provides a handle identifier to use later, lets call it "h1" (e.g., h1 can be "12")
*
* 2> Load in the customer's KEK in a permenant key using 'h1'
* Command: imSymKey -w 12 -t 31 -f aes256.key -l P6RKEK1 (12 is an example h1)
* The result of this command will also be to return the handle identifier of our loaded KEK, lets call it "h2" (e.g., h2 can be "13")
*
* 3> Verify customer's KEK attributes
* Command: getAttribute -o 13 -a 512 -out keyinfo
* (Verify that CKA_WRAP and CKA_UNWRAP are set to OxO1, if not set then via setAttribute command line operation)
*
* 4> Optional, we can now export the application key using the customer's KEK, KSG will do this via PKCS#11
* Command: exSymKey -w 13 -k 6 -out exported2
* "-w" is for the handle identifier of our loaded KEK (i.e., h2), while "-K" is the handle identifier of the key we want to export
*

Entrust nShield Connect\Edge HSM (formerly nCipher) Set Up

After installing KSG make sure to copy the cknfast-64.dll (for Windows) or libcknfast.so (for Linux) file into the KSG "components" directory. This allows KSG to find and load the Entrust PKCS#11 library and use it to talk to the HSM.

To modify the bahaivor of the nShield Connect a user can set either environment variables or create a "cknfastrc" file for the HSM to read. The cknfastrc file that we used for this integration is as follows:

* CKNFAST_OVERRIDE_SECURITY_ASSURANCES=explicitness;tokenkeys;longterm
* CKNFAST_FAKE_ACCELERATOR_LOGIN=1
*

Note that in addition to the parameters set above, we routinely set CKNFAST_DEBUG=9 and CKNFAST_DEBUGFILE to log the actions taken by the HSM and there results. Please refer to Entrust documentation for a description of the settings above.

The Entrust HSM uses Vendor Defined mechanisms for HMAC key generation. Instead of the PKCS#11 V2.40 standard where HMACs are created via key generation Entrust uses the C_GenerateKey() API. P6R's KSG handles this difference but requires the calling KMIP application to use the KMIP Create operation instead of the KMIP Derive Key operation to create a HMAC key when using an Entrust nShield HSM. Note, that this also requires that the "HSM_type" KSG configuration parameter must be set with the Entrust nShield defined value (see above).

Unlike the AWS CloudHSM and Cavium HSMs, the integration with the Entrust nShield Connect does not support the KMIP Get operation since we did not find anyway to inject a customer provided KEK into the HSM. Thus keys created on the nShield Connect could only be extracted from the HSM using wrapping keys created on the HSM.

We performed integration testing with the nShield Edge (which provides the same API as the Connect). Specifics of the HSM we used where discovered by calling the PKCS#11 API function C_GetTokenInfo():

* ...bin>p6pkcs11tool -lt 0
* p6pkcs11Tool v2019.1.23062 - Copyright 2004-2019 P6R Inc - All Rights Reserved
*
* ------- Token Details -------
* Slot Id: 0
* Label: [accelerator]
* Manufacturer Id: [nCipher Corp. Ltd]
* Serial Number: [2D77-39B3-D9FE]
* Flags: 209
* Flag set: CKF_RNG
* Flag set: CKF_USER_PIN_INITIALIZED
* Flag set: CKF_DUAL_CRYPTO_OPERATIONS
* Max PIN length: 256
* Min PIN length: 0
* Hardware Version: 0.11
* Firmware Version: 2.61
*

Are you running an older version of KSG?

Upgrading to KSG 2020.x requires a keystore with database schema version "M1.5". Previous versions of KSG used keystore database schema version "1.4". Please apply the appropriate SQL upgrade commands defined below depending on the database in use.

FIRST before performing any of the SQL commands below make a backup of the SQlite or Postgres database being used by KSG.

[A] SQlite database SQlite has limited support for the "ALTER TABLE ..." command. Thus the following steps are required to change the SQL UNIQUE constraint. Use a SQL command line (e.g, SQLiteSpy).

Step 1: Verify schema in use

* select * from ks_constants;
*

If you see name: "P6R Schema Version", value: "1.4", then run step two below. Otherwise, if you see "M1.5" the database scheme is correct and you are done.

Step 2: SQLite does not support all of "Alter table".

* PRAGMA foreign_keys=off;
*
* BEGIN TRANSACTION;
*
* ALTER TABLE ks_attributes ADD instanceNumber INTEGER NOT NULL default 0;
*
* -- should show a new column 'instanceNumber'
* SELECT * FROM ks_attributes;
*
* ALTER TABLE ks_attributes RENAME TO old_ks_attributes;
*
* CREATE TABLE ks_attributes( id INTEGER PRIMARY KEY AUTOINCREMENT,
* object_id INTEGER NOT NULL,
* name VARCHAR(300) NOT NULL,
* valueStr VARCHAR(3000) NULL,
* valueDate INTEGER NULL,
* valueInt INTEGER NULL,
* instanceNumber INTEGER NOT NULL default 0,
* FOREIGN KEY (object_id) REFERENCES ks_keys( id ) ON DELETE CASCADE,
* UNIQUE ( object_id, name, instanceNumber ) );
*
* INSERT INTO ks_attributes SELECT * FROM old_ks_attributes;
*
* -- new table created with new UNIQUE constraint and new column
* SELECT * FROM ks_attributes;
*
* DROP TABLE old_ks_attributes;
*
* UPDATE ks_constants SET value='M1.5' WHERE name='P6R Schema Version';
*
* COMMIT;
*
* PRAGMA foreign_keys=on;
*

[B] Postgres database This database has a full "ALTER table" support.

Step 1: Verify schema in use

* select * from ks_constants;
*

If you see name: "P6R Schema Version", value: "1.4", then run step two below. Otherwise, if you see "M1.5" the database scheme is correct and you are done.

Step 2: Run several Alter table commands

* ALTER TABLE ks_attributes ADD instanceNumber INTEGER NOT NULL default 0;
*
* Verify the Unique constraint name by typing: \d ks_attributes
* Which will likely provide the name "ks_attributes_object_id_key" for the "UNIQUE, btree (object_id, name)"
*
* ALTER TABLE ks_attributes DROP CONSTRAINT ks_attributes_object_id_key;
*
* ALTER TABLE ks_attributes ADD UNIQUE ( object_id, name, instanceNumber );
* Verify new unique constraint by again typing: \d ks_attributes
*
* UPDATE ks_constants SET value='M1.5' WHERE name='P6R Schema Version';
* Verify change by typing: SELECT * FROM ks_constants;
*