1. Article purpose[edit | edit source]
The main purpose of this article is to explain how to use 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 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 will be useful for people wanting 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. That can be done by interfacing an HSM where the secrets are securely stored to a signing tool.
4. Prerequisites[edit | edit source]
Following this article, it is mandatory that:
- That the HSM you are using can be accessed using PKCS#11 APIs
- You are running an OpenSSL version supporting engines. OpenSSL engines are deprecated [2] since OpenSSL version 3.0 but are still implemented. Therefore most of versions of OpenSSL above 0.9.6 should fit to perform the operation.
- You have generated a key pair and stored the private key in the HSM
Information |
Some packages like OpenSSL are already included in the OSTL SDK. |
5. Perform a binary signature[edit | edit source]
First, check openSSL version:
openssl version OpenSSL 3.2.2 4 Jun 2024 (Library: OpenSSL 3.2.2 4 Jun 2024)
Check that 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 wish 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 will 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 paths to *.pem files.
Information |
The PKCS#11 URLs must be enclosed with the double quote (") character. E.g: ROT_KEY="\"<PKCS11_URL_OF_THE_PRIVATE_KEY>\"" |
6. Example with a software HSM[edit | edit source]
6.1. Extra prerequisites[edit | edit source]
In this example, the HSM will be software. We will use SoftHSMv2 [3] that is a software implementation of a generic cryptographic device with a PKCS#11 interface. To set up the environment, we need to:
- Make sure the following packages are installed:
- pkcs11-tools that is provided in the opensc package
- p11tool that is provided in the gnutls-bin package
- libengine-pkcs11-openssl
- Install SoftHSMV2
6.2. Setup[edit | edit source]
Fields enclosed <this_way> are supposed to be replaced by your absolute paths.
- First, we need to create a working directory where we will be storing configuration files and tokens.
cd $HOME mkdir -p softhsm/tokens cd softhsm
- Copy SoftHSMv2 default configuration file
cp /etc/softhsm2.conf .
- Custom the token directory path in this configuration file
Insert "directories.tokendir = <path_to>/softhsm/tokens" in softhsm2.conf
- Export SOFTHSM2_CONF environment variable
export SOFTHSM2_CONF=<path_to>/softhsm/softhsm2.conf
- Show 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 token with a given label. SO PIN is the administrator PIN, User PIN will be 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 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
Information |
To ease manipulations, you can create an alias to: pkcs11-tool --module /usr/local/lib/softhsm/libsofthsm2.so |
alias p11-softhsm="pkcs11-tool --module /usr/local/lib/softhsm/libsofthsm2.so"
- List 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 (e.g: 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.
Information |
At this stage, and similarly to the procedure above, the PKCS11 URLs can be used to generate the CoT certificates |
7. Troubleshooting[edit | edit source]
- If you can't enumerate slots like:
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
That means the openSSL configuration file is incorrect or that the OPENSSL_CONF variable hasn't been defined, please check it.
- If you can't find the key:
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
This is likely that your SOFTHSM2_CONF variable hasn't been set or that you configuration file isn't correct.
8. References[edit | edit source]