Last edited 3 weeks ago

How to sign a software image using an external HSM


1. Article purpose[edit | edit source]

The main purpose of this article is to explain how to use the secrets stored in an external Hardware Security Module (HSM) to sign a software image such as TF-A BL2 or even a FIP. This allows the user to perform a Trusted boot by establishing a Chain of Trust (CoT).

2. OSTL implementation[edit | edit source]

In the OSTL ecosystem, the Signing tool is used to sign the platform Trusted Firmware-A BL2 software that is loaded by the ROM code. The Trusted Firmware-A FIP contains the firmware images loaded by the Trusted Firmware-A BL2 and their configuration files. The cert_create tool [1] handles the signature and the certificate chain generation for the binaries contained in the FIP. Both tools support the use of an external HSM.

3. Use case[edit | edit source]

This article is useful for people who want to sign firmware without having to manipulate a plain private key at some point. One may not want such secrets to be accessible at all. This can be done by interfacing an HSM where the secrets are securely stored with a signing tool.

4. Prerequisites[edit | edit source]

Following this article, it is mandatory that:

  • The HSM you are using can be accessed using PKCS#11 APIs.
  • You are running an OpenSSL version that supports engines. OpenSSL engines are deprecated [2] since OpenSSL version 3.0 but are still implemented. Therefore, most OpenSSL versions above 0.9.6 should fit to perform the operation.
  • You have generated a key pair and stored the private key in the HSM.

5. Perform a binary signature[edit | edit source]

First, check the openSSL version:

openssl version
OpenSSL 3.2.2 4 Jun 2024 (Library: OpenSSL 3.2.2 4 Jun 2024)

Check that the PKCS#11 engine is correctly set:

openssl engine pkcs11 -t
(pkcs11) pkcs11 engine
    [ available ]

Create a custom openSSL configuration file containing:

openssl_conf = openssl_conf

[openssl_conf]
engines = engine_section

[engine_section]
pkcs11 = pkcs11_section

[pkcs11_section]
engine_id = pkcs11
dynamic_path = <path_to_libpkcs11.so> #Usually /usr/lib/x86_64-linux-gnu/engines-xxx/libpkcs11.so
MODULE_PATH = <path_to_HSM_module_library>

and use it as openSSL configuration file:

export OPENSSL_CONF=<path_to_your_custom_config_file>

5.1. Perform a signature using only openSSL[edit | edit source]

Simply use the PKCS#11 URL of the private key that you want to use to perform the signature:

openssl dgst -engine pkcs11 -sign "<PKCS11_URL_OF_THE_PRIVATE_KEY>" -keyform engine -out test_signed.bin test.txt
engine "pkcs11" set.

Note that this does not generate the certificates necessary to implement the CoT.

5.2. Perform Trusted Firmware-A FIP signature with PKCS#11[edit | edit source]

At this stage, the process is exactly the same as the one described in the TF-A BL2 Trusted Board Boot article. Simply specify the PKCS#11 URLs in the key arguments instead of the paths to *.pem files.

6. Example with a software HSM[edit | edit source]

6.1. Additional prerequisites[edit | edit source]

This section shows an example of software HSM. The SoftHSMv2 [3] is used, which is a software implementation of a generic cryptographic device with a PKCS#11 interface. To set up the environment:

  • Make sure the following packages are installed:
    • pkcs11-tools provided in the opensc package
    • p11tool provided in the gnutls-bin package
    • libengine-pkcs11-openssl
  • Install SoftHSMV2.

6.2. Setup[edit | edit source]

The fields enclosed <this_way> are supposed to be replaced by your absolute paths.

  • First, create a working directory to store the configuration files and tokens:
cd $HOME
mkdir -p softhsm/tokens
cd softhsm
  • Copy the SoftHSMv2 default configuration file:
cp /etc/softhsm2.conf .
  • Customize the token directory path in this configuration file:

Insert "directories.tokendir = <path_to>/softhsm/tokens" in softhsm2.conf

  • Export the SOFTHSM2_CONF environment variable:
export SOFTHSM2_CONF=<path_to>/softhsm/softhsm2.conf
  • Display the slots:
softhsm2-util --show-slots
Available slots:
Slot 0
   Slot info:
       Description:      SoftHSM slot ID 0x0
       Manufacturer ID:  SoftHSM project
       Hardware version: 2.6
       Firmware version: 2.6
       Token present:    yes
   Token info:
       Manufacturer ID:  SoftHSM project
       Model:            SoftHSM v2
       Hardware version: 2.6
       Firmware version: 2.6
       Serial number:
       Initialized:      no
       User PIN init.:   no
       Label:
  • Initialize the token with a given label. SO PIN is the administrator PIN, User PIN is used to access the slot:
softhsm2-util --init-token --slot 0 --label "TFASignFIP"
=== SO PIN (4-255 characters) ===
Please enter SO PIN: **** #0000
Please reenter SO PIN: ****
=== User PIN (4-255 characters) ===
Please enter user PIN: **** #1234
Please reenter user PIN: ****
The token has been initialized and is reassigned to slot 1861710895
  • Check the module:
pkcs11-tool --show-info --module /usr/local/lib/softhsm/libsofthsm2.so
Cryptoki version 2.40
Manufacturer     SoftHSM
Library          Implementation of PKCS11 (ver 2.6)
Using slot 0 with a present token (0x6ef7742f)  #1861710895
alias p11-softhsm="pkcs11-tool --module /usr/local/lib/softhsm/libsofthsm2.so"
  • List all the available slots:
p11-softhsm --list-slots
Available slots:
Slot 0 (0x6ef7742f): SoftHSM slot ID 0x6ef7742f
 token label        : TFASignFIP
 token manufacturer : SoftHSM project
 token model        : SoftHSM v2
 token flags        : login required, rng, token initialized, PIN initialized, other flags=0x20
 hardware version   : 2.6
 firmware version   : 2.6
 serial num         : 1eb49a0ceef7742f
 pin min/max        : 4/255
Slot 1 (0x1): SoftHSM slot ID 0x1
 token state:   uninitialized
  • Generate a keypair using pkcs11-tools:
p11-softhsm --login --login-type user --keypairgen --id 0 --key-type EC:secp256r1 --slot 1861710895
Logging in to "TFASignFIP".
Please enter User PIN: #Enter User PIN
Key pair generated:
Private Key Object; EC
 label:
 ID:         00
 Usage:      decrypt, sign, unwrap, derive
 Access:     sensitive, always sensitive, never extractable, local
Public Key Object; EC  EC_POINT 256 bits
 EC_POINT:   044104510cedc7dabaa4b3a7f9953069065d3f9b3978d772e3c04069c34f4198a5bda64e16ec685c9dadbe91c5f35a76362d8c955a4167e78e3f1365e98ab05f7884a4
 EC_PARAMS:  06082a8648ce3d030107
 label:
 ID:         00
 Usage:      encrypt, verify, wrap, derive
 Access:     local
  • List and get the private key URL with p11tool:
p11tool --provider=/usr/local/lib/softhsm/libsofthsm2.so --login --set-pin=1234 --list-all
Object 0:
	URL: pkcs11:model=SoftHSM%20v2;manufacturer=SoftHSM%20project;serial=1eb49a0ceef7742f;token=TFASignFIP;id=%00;type=private #This is the URI
	Type: Private key (EC/ECDSA-SECP256R1)
	Label:
	Flags: CKA_WRAP/UNWRAP; CKA_PRIVATE; CKA_NEVER_EXTRACTABLE; CKA_SENSITIVE;
	ID: 00

Object 1:
	URL: pkcs11:model=SoftHSM%20v2;manufacturer=SoftHSM%20project;serial=1eb49a0ceef7742f;token=TFASignFIP;id=%00;type=public
 	Type: Public key (EC/ECDSA-SECP256R1)
	Label:
	Flags: CKA_WRAP/UNWRAP;
	ID: 00
  • Create a custom openSSL configuration file (for example openssl-pkcs11.conf) with the content described here, and add:
MODULE_PATH = /usr/local/lib/softhsm/libsofthsm2.so
  • Export the OPENSSL_CONF environment variable:
export OPENSSL_CONF=<path_to>/softhsm/openssl-pkcs11.conf
  • Sign a binary using the PKCS11 URL:
openssl dgst -engine pkcs11 -sign "pkcs11:model=SoftHSM%20v2;manufacturer=SoftHSM%20project;serial=1eb49a0ceef7742f;token=TFASignFIP;id=%00;object=tfasign;type=private" -keyform engine -out test_signed.bin test.txt
engine "pkcs11" set.

7. Troubleshooting[edit | edit source]

  • If you cannot enumerate slots as shown below, it means that the openSSL configuration file is incorrect or that the OPENSSL_CONF variable has not been defined. In this case, please check it.
openssl dgst -engine pkcs11 -sign "pkcs11:model=SoftHSM%20v2;manufacturer=SoftHSM%20project;serial=1eb49a0ceef7742f;token=TFASignFIP;id=%00;object=tfasign;type=private" -keyform engine -out signature.bin test.txt
engine "pkcs11" set.
Failed to enumerate slots
Failed to enumerate slots
PKCS11_get_private_key returned NULL
cannot load key file from engine
140310533596480:error:80067065:pkcs11 engine:ctx_load_privkey:object not found:eng_back.c:858:
140310533596480:error:26096080:engine routines:ENGINE_load_private_key:failed loading private key:../crypto/engine/eng_pkey.c:77:
unable to load key file 
  • If you cannot find the key, it is likely that your SOFTHSM2_CONF variable has not been set or that you configuration file is not correct.
openssl dgst -engine pkcs11 -sign "pkcs11:model=SoftHSM%20v2;manufacturer=SoftHSM%20project;serial=1eb49a0ceef7742f;token=TFASignFIP;id=%00;object=tfasign;type=private" -keyform engine -out signature.bin test.txt
engine "pkcs11" set.
Specified object not found
Specified object not found
PKCS11_get_private_key returned NULL
cannot load key file from engine
140107714262336:error:80067065:pkcs11 engine:ctx_load_privkey:object not found:eng_back.c:858:
140107714262336:error:26096080:engine routines:ENGINE_load_private_key:failed loading private key:../crypto/engine/eng_pkey.c:77:
unable to load key file
Segmentation fault

8. References[edit | edit source]