FM development
This chapter outlines the development life cycle of your FM SDK, and other related topics.
Life-cycle outline
The following diagram illustrates the recommended development cycle to be undertaken when developing functionality modules for a ProtectServer 3 HSM.
FM development life cycle
As shown in the diagram, the flow of development activities is comprised of the following stages:
-
Initial development: Includes the design and development of the functionality application code for initial testing.
-
Emulation build: This process compiles the FM code for the emulation environment.
-
Emulation test: The FM produced during the previous steps should now be completely tested in emulation mode to ensure correct operation. Should errors be found in the emulation build, the developer should repeat the build/test/debug cycle until successful operation is confirmed.
-
Adapter build: The functionality module should now be built for the HSM environment. The FM is downloaded onto the HSM hardware and again tested to ensure it operates as expected.
-
Production build: Finally, the FM is produced and released for the operational environment it was intended.
Initial development
This phase begins development, from the specification of the requirements to the completion of the design. Programming the FM, and the host-side libraries and/or application can also be considered part of this stage. It is assumed that at this stage, the test procedures are also developed.
Emulation build
In this phase, the FM and the host-side libraries and applications are built for the emulation environment.
This stage is complete when the FM executes correctly within the emulation DLL, and the host-side executables (and possibly the DLLs) are generated successfully.
Emulation test
The test procedures must have been created prior to this stage. The emulation binaries generated in the previous stage are used to execute the test procedures and determine whether the FM satisfies its requirements. Since the message dispatching code is not compiled in the emulation build, tests for problems in serialization of data do not need to be performed in this stage.
The development usually stays in the Emulation Build/Emulation Test loop until all the problems detected are fixed. During this stage, developers are encouraged to use a debugger to step through the FM as well as the host source code.
Adapter build
After the emulation build passes all the tests, the FM must be tested in the HSM. Although the emulation build is a very close approximation of the HSM environment, there are components such as function patching and the dispatch/retrieval of messages between the host and HSM, which are not tested during the emulation test stage.
In this phase, the developer generates the binary FM image and signs it using either a temporary or a permanent development key. Once the image is signed, it can be downloaded to the HSM for the next stage of testing.
Adapter test
In the HSM test stage, the development build of the FM is tested in its production environment. The tests performed in the emulation environment should also be repeated, to validate the implementation.
If problems are detected in this stage, the developer can choose to resolve them in the emulation test stage or the HSM test stage. The choice usually depends on the seriousness of the problem and the area in which the problem was detected. Since the message serialization code is not compiled in the emulation environment, it is unnecessary to go back to the emulation build stage when a problem in this area is detected.
Production build
When convinced that the implementation of the FM and the host side code is correct, a production build of the system is performed.
In this stage, the developer generates the FM binary image, and the responsible person signs it using the production private key.
Acceptance test
When the production binaries are available, the acceptance tests are performed on the final system before the binaries are released.
Key management
All FM images downloaded to the HSM must have an assigned signature. FMs are only executed inside the HSM after this signature has been validated. The management of the keys used to sign/verify the firmware is completely controlled by the developers of the FM. Thales does not have any responsibility for the FM key management scheme.
The certificate used to validate the FM binary image must exist in the Admin Token of the HSM where the FM is to be installed. If the certificate does not already exist in the Admin Token, the Administrator will be required to install the certificate in the Admin Token. Furthermore, the verification and downloading of the FM requires the HSM Administrator to provide the Admin Token password, enforcing the presence of the HSM Administrator at the time of the download operation.
As previously advised, there is no pre-defined key management scheme for the private key and the certificate. The FM developer must decide early on the key management scheme to be used in the system.
Example key-management scheme
This sample approach to a key management scheme can be customized and extended.
It is recommended that the key used to sign FMs in the Adapter Build phase is not the same as the key used to sign it in the Production Build phase. This would ensure that an FM in the Adapter Build or Adapter Testing phase cannot be used by end-users or customers. Additionally, a production-level FM signing key requires stricter access control than the development signing keys. Using this key to sign FM images in the Adapter Build phase would make development more difficult.
The simplest development key management scheme is to generate a new self-signed key/certificate pair every time the FM image is created. This can be done using the ProtectToolkit-C ctcert tool. Please note that the signing key cannot be used from the Admin Token because of limitations on how the mkfm utility addresses keys. Therefore, the key/certificate pair must be created on another token and the certificate must be imported into the Admin Token. Importing can be done either by backing up the certificate on smartcards and restoring it to the Admin Token, or exporting the certificate to a file and then re-importing it into the Admin Token using the ctcert tool.
After the certificate is in the Admin Token, the Admin Token SO must login to the token and mark the certificate as “trusted”. This can be achieved using the ctcert tool.
After the certificate is marked as trusted, the raw FM binary image can be signed with the generated private key, using the mkfm utility. The signed FM image can then be downloaded into the HSM using the ctconf utility.
There must be a non-development HSM to hold the production key/certificate pair. The key/certificate pair used to sign a production FM can use the most appropriate of the following three approaches:
Self-signed certificate
This scheme does not provide any authentication of the FM. However, it is very easy to set up and use. If the certificate must be handed to a third party, it must be done using a trusted channel - treating the certificate as a secret key. This scheme is most suitable for companies developing FMs for internal use only.
Certificate signed by a trusted third party
The signing key and the certificate are obtained from a trusted third-party CA. This scheme ensures the authenticity of the certificate, and allows the certificate to be transmitted to another party over an untrusted channel.
Use of a local CA signing key
This scheme requires the FM developers to obtain a signing key/certificate from a trusted third party for local CA operations. Then, another signing key/certificate pair is generated locally for signing production-level FMs. This allows multiple signing keys to be created, authenticating each FM separately.
Contents of the $(FMSDK) directory
When installed for FM development (as opposed to host only development) the $(FMSDK) directory contains the following:
Directory or file | Description |
---|---|
bin/ | Non-toolchain utilities and tools for creating an FM |
Doc/ | FM Development documentation |
Include/ | Header files specific to FM and FM Host Application development. These are used together with headers provided by ProtectToolkit-C in $(CPROVDIR)/ include. |
lib/ppcfm/ | Static libraries used for building an FM that will run in a ProtectServer 3 PCIe HSM. |
lib/linux-i386/ | Static libraries used for building an emulation mode FM that will run on the host computer. |
samples/ | Sample FMs and FM Host applications described below. |
src/emul/ | Source files used for building wrapper cryptoki and ethsm libraries required with FM emulation. |
cfgbuild.mak | Common configuration makefile that sets up makefile and toolchain variables and rules required for building an FM. This should be included at the top of any FM’s makefile. |
fmconfig.mk | Common configuration makefile that finds the toolchain and sets up FM binaries correctly. This should be included at the top of any FM’s makefile. |
SDK installation tips
When installing the FM SDK, it defaults to a system installation path. As long as CPROVDIR and FMDIR are set to the system paths, the samples can be copied elsewhere so they can be built and modified by a non-root user.
Protecting data storage of FM
When the FM is used to extend HSM functionality, there is usually data that must be protected by the HSM. Normally, this data would be stored in one of the tokens as a Cryptoki Object. Protection of these objects poses a problem, however, because setting the SENSITIVE attribute on the object would prevent access from the FM, and leaving it open would allow access to any PKCS#11 application on the host side.
There are three possible solutions to this problem:
-
Token blocking
-
Using Privilege Level
-
Using the SMFS
Token blocking
As shown in the sample FM restrict, the FM can patch the C_OpenSession() PKCS#11 function, preventing any session from being open to the slot containing the objects used by the FM. In PKCS#11, all functions that can access or export the object need a session handle to the token containing the object, and the FM patches the C_OpenSession() to prevent applications from obtaining the required session handle. This method effectively reserves one or more tokens of the HSM for the FM's internal use, and prevents any kind of access to the contents of this token from the host side.
Using privilege level
The CT_SetPrivilegeLevel function allows a simple solution. As shown in the cipherobj and oaepcipherobj sample FMs, the FM can make a call to temporarily obtain the rights to read Sensitive object attributes.
This allows the FM designer to create and manage keys using the tools provided with the HSM, so they are safe from outside programs but still accessible from the trusted FM.
Using the SMFS
The Secure Memory File System provides access to the same low-level key storage facility. By creating a new application directory, the FM designer can store keys without them being visible through the HSM's Cryptoki interface.
The key format is up to the FM designer - they need not have attributes as Cryptoki objects do.
There is no need to call C_Initialize, open sessions, or search for object handles if you use the SMFS to store your keys.
FMs that store their keys in SMFS need to provide all the functions to generate, store, delete, backup, and restore these keys.
When creating FMs that open an SMFS file and keep the handle open, developers should note:
When an application calls C_Initialize for the first time after the HSM is restarted, the HSM firmware will close all SMFS handles. So if you open an SMFS file during startup, the next C_Initialize call will close the file. Also, the number of SMFS file handles is a limited resource (approx 16).
Therefore, FM designers should not keep SMFS file handles. Instead, only use SMFS to back up the keys.
Keep the keys in normal memory while the FM is running. Restore the keys from SMFS during the FM initialization by opening/reading and closing the SMFS file. When changes are made to the keys, open/write/close the SMFS file to back up the changes.
Cprov function patching
Downloading bad FM code into the HSM could make the device unusable. Patching functions such as C_Initalize, C_OpenSession, C_Login and C_VerifyXXX must be done with extreme care.
One technique is to put safety switches in the startup function, as seen in the sample FM safedebug.
FM message dispatching
FM Message Dispatching support allows for more than one request buffer and reply buffer to be presented to the HSM. The message dispatch layer provides scatter-gather support, to combine all the request buffers into a single data buffer and send it to the HSM. The reply data is treated the same way, but in reverse; the data is scattered into multiple reply buffers. This feature can be very useful when information sent to the HSM and information received from the HSM are kept in different variables and / or buffers.
The scatter-gather operation on the reply buffers can behave in an unintuitive manner when the initial buffers are of variable length. The device driver will start filling the host-side initial buffers with the reply data, and it will not place any data into subsequent buffers until the current one is completely filled. This means the reply buffer fields may not contain the expected values when the amount of data placed in a variable-length buffer is less than the maximum length of the buffer.
For example, if two reply buffers of 40 bytes each are passed to the message dispatch layer, but the actual data to be returned in each buffer is only 32 bytes, the first 40-byte buffer will be filled with 32 bytes of data meant for the first buffer and 8 bytes of data meant for the second buffer. The second reply buffer of 40 bytes will only contain 26 bytes of data.
There are two possible ways to handle this:
-
After receiving the reply, realign the data in the buffers. The order of realignment must be from the last buffer to the first. In order to implement this, the reply data in its entirety must contain enough information to determine the length of each reply block.
-
Always merge the reply buffers to a single block before dispatching the request, by allocating another block and moving data from the allocated buffer to the caller’s reply buffers. This approach makes the code more reliable.
Handling host processes
The FM SDK allows an FM developer to determine the identity of processes sending messages to the HSM.
The functions FM_GetCurrentPid and FM_GetCurrentOid allow you to know what process is sending the current message. You must use a combination of PID and OID to uniquely identify a process; i.e. if two callers have the same PID but different OIDs, they should be seen by the FM as different processes.
If your Functionality Module supports the concept of a user login, you will need to track which host processes have logged on.
Therefore, you can remember which process has logged on by storing the PID and the OID as the process successfully authenticates. When a process sends a message that requires authentication, you can check to see if the process is in the list of authenticated processes.
The Cryptoki system always uses the PID/OID to determine if a session handle or object handle is valid for the calling process.
Therefore, if the FM makes Cryptoki calls while processing a request, and it is using a session handle obtained earlier from a different request, there is a possibility that the Cryptoki call with fail with a CKR_CRYPTOKI_NOT_INITIALIZED error.
This occurs because Process A calls the FM, which calls C_Initialize and opens a Cryptoki session. Later, Process B calls the FM and the FM tries to use the session handle. The Cryptoki will not recognise Process B. To overcome this problem, you can modify the PID and OID to a constant value that the underlying Cryptoki sees by using the FM_SetCurrentPid and FM_SetCurrentOid calls prior to making any Cryptoki calls.
The value -1 for PID and OID is a suitable choice for this purpose.
Memory alignment issues
The PowerPC processor in the ProtectServer 3 PCIe,ProtectServer 3 External, andProtectServer 3+ External HSMs does not require fully aligned memory access, but unaligned access incurs a performance cost.
Memory endian issues
The processor in the ProtectServer 3 PCIe HSM is big endian, while processors in modern clients, such as clients running Windows operating systems, are usually little endian.
It is recommended that FM developers use the provided endian macros to encode all messages in network byte order. By using the endian macros on both host and FM, endian differences between host and HSM are not an issue.
The utility endian macros are provided in the ProtectToolkit-C header file endyn.h.
FMs remain after tampering the HSM
FMs that have been loaded onto the HSM are not deleted from the HSM after a tamper event. FMs must be deleted by using the ctfm utility, as described in Delete an FM from the HSM, before tampering the HSM. For more information about tampering the HSM, refer to Tampering or decommissioning the HSM.
Data processing limitation
If you are using ProtectToolkit 7.2.0 or newer with ProtectServer 3 HSM Firmware 7.01.02 or newer, host applications and FMs can exchange messages that are up to 64 MB in size by using the MD_SendReceive or FMSC_SendReceive functions. However, the FM completes cryptographic operations on requests that are larger than 64 KB by processing the provided data in 64 KB chunks. To avoid running into issues, Thales recommends developing FM code that splits messages that are larger than 64 KB into multiple requests that are less than 64 KB. For example, break up one call to C_Encrypt with more than 64 KB of data into multiple C_EncryptUpdate calls that are less than 64 KB.