Add testPreLoadHsmSign, a functional test that exercises end-to-end pre-load header signing using SoftHSM as a PKCS#11 token.
Signed-off-by: Yan WANG <[email protected]> --- tools/binman/ftest.py | 64 +++++++++++++++++ .../test/security/pre_load_hsm_sign.dts | 68 +++++++++++++++++++ 2 files changed, 132 insertions(+) create mode 100644 tools/binman/test/security/pre_load_hsm_sign.dts diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py index 2fb452b4e46..329b91dfd06 100644 --- a/tools/binman/ftest.py +++ b/tools/binman/ftest.py @@ -5931,6 +5931,70 @@ fdt fdtmap Extract the devicetree blob from the fdtmap self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)]) self.assertEqual(is_signed, True) + def testPreLoadHsmSign(self): + """Test an image with a pre-load header signed using HSM (SoftHSM)""" + # Check for required bintools + softhsm2_util = bintool.Bintool.create('softhsm2_util') + self._CheckBintool(softhsm2_util) + + pkcs11_tool = bintool.Bintool.create('pkcs11-tool') + self._CheckBintool(pkcs11_tool) + + # Place holder of public key file + public_key = self._MakeInputFile("public.key", b"") + pubkey_der = self._MakeInputFile("pubkey.der", b"") + + # Create AES key for FIT encryption (required by pre_load_hsm_sign.dts) + # Put it in a subdirectory to avoid polluting the main input directory + data = tools.read_file(self.TestFile("fit/aes256.bin")) + self._MakeInputFile("hsm_keys/aes256.bin", data) + + prefix = "testPreLoadHsmSign." + + # Configure SoftHSMv2 + data = tools.read_file(self.TestFile('fit/softhsm2.conf')) + softhsm2_conf = self._MakeInputFile(f'{prefix}softhsm2.conf', data) + softhsm2_tokens_dir = self._MakeInputDir(f'{prefix}softhsm2.tokens') + + with open(softhsm2_conf, 'a') as f: + f.write(f'directories.tokendir = {softhsm2_tokens_dir}\n') + + # Set up HSM environment and build image + with unittest.mock.patch.dict('os.environ', + {'SOFTHSM2_CONF': softhsm2_conf}): + # Initialize token + softhsm2_util.run_cmd('--init-token', '--free', '--label', + 'uboot-hsm', '--pin', '1234', + '--so-pin', '1234') + + # Generate key pair directly in SoftHSM + pkcs11_tool.run_cmd('--module', '/usr/lib/softhsm/libsofthsm2.so', + '--keypairgen', '--key-type', 'rsa:2048', + '--label', 'uboot-key', '--login', '--pin', '1234') + + # Extract public key from SoftHSM + pkcs11_tool.run_cmd('--module', '/usr/lib/softhsm/libsofthsm2.so', + '--read-object', '--type', 'pubkey', + '--label', 'uboot-key', '--login', '--pin', '1234', + '--output-file', pubkey_der) + tools.run('openssl', 'rsa', '-pubin', '-inform', 'DER', + '-in', pubkey_der, '-out', public_key) + + # Build image with HSM signing + hsm_keys_subdir = os.path.join(self._indir, "hsm_keys") + data = self._DoReadFileDtb('security/pre_load_hsm_sign.dts', + use_expanded=True, + extra_indirs=[hsm_keys_subdir])[0] + + image_fname = tools.get_output_filename('image.bin') + is_signed = self._CheckPreload(image_fname, public_key) + # Verify pre-load header structure + self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)]) + self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)]) + self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)]) + self.assertEqual(is_signed, True) + + def _CheckSafeUniqueNames(self, *images): """Check all entries of given images for unsafe unique names""" for image in images: diff --git a/tools/binman/test/security/pre_load_hsm_sign.dts b/tools/binman/test/security/pre_load_hsm_sign.dts new file mode 100644 index 00000000000..bb6bf562b2b --- /dev/null +++ b/tools/binman/test/security/pre_load_hsm_sign.dts @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Test device tree for pre-load with SoftHSM signing + +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + pre-load { + content = <&image>; + algo-name = "sha256,rsa2048"; + header-size = <4096>; + version = <0x11223344>; + hsm-support; + hsm-library = "/usr/lib/softhsm/libsofthsm2.so"; + hsm-token-label = "uboot-hsm"; + hsm-key-label = "uboot-key"; + hsm-pin = "1234"; + }; + + image: fit { + fit,encrypt; + description = "Test a FIT with encrypted data and signed with a preload"; + #address-cells = <1>; + + images { + u-boot { + description = "U-Boot"; + type = "firmware"; + arch = "arm64"; + os = "U-Boot"; + compression = "none"; + load = <00000000>; + entry = <00000000>; + cipher { + algo = "aes256"; + key-name-hint = "aes256"; + }; + u-boot-nodtb { + }; + }; + fdt-1 { + description = "Flattened Device Tree blob"; + type = "flat_dt"; + arch = "arm64"; + compression = "none"; + cipher { + algo = "aes256"; + key-name-hint = "aes256"; + }; + u-boot-dtb { + }; + }; + }; + + configurations { + default = "conf-1"; + conf-1 { + description = "Boot U-Boot with FDT blob"; + firmware = "u-boot"; + fdt = "fdt-1"; + }; + }; + }; + }; +}; -- 2.43.0
