Add a test that signs a pre-load header through the pkcs11 engine, with a key imported into SoftHSM, like the existing FIT signature tests. It is skipped when softhsm2-util is not installed.
Assisted-by: Claude:claude-opus-5 Signed-off-by: Lorenz Kofler <[email protected]> --- tools/binman/ftest.py | 79 +++++++++++++++++++ .../test/security/pre_load_engine_pkcs11.dts | 24 ++++++ .../security/pre_load_engine_pkcs11_pss.dts | 24 ++++++ 3 files changed, 127 insertions(+) create mode 100644 tools/binman/test/security/pre_load_engine_pkcs11.dts create mode 100644 tools/binman/test/security/pre_load_engine_pkcs11_pss.dts diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py index 63fbf50089f..8238ac151ce 100644 --- a/tools/binman/ftest.py +++ b/tools/binman/ftest.py @@ -5922,6 +5922,85 @@ 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 _SetupPreLoadEngine(self, prefix): + """Set up a SoftHSM token holding the key used by the engine tests + + Args: + prefix (str): Prefix for the files created in the input directory + + Returns: + str: Filename of the SoftHSM configuration file + """ + softhsm2_util = bintool.Bintool.create('softhsm2_util') + self._CheckBintool(softhsm2_util) + + try: + tools.run('openssl', 'engine', 'dynamic', '-c', 'pkcs11') + except ValueError: + self.skipTest('PKCS11 engine setup not functional, ' + 'did you install libengine-pkcs11-openssl?') + + 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') + + with unittest.mock.patch.dict('os.environ', + {'SOFTHSM2_CONF': softhsm2_conf}): + softhsm2_util.run_cmd('--init-token', '--free', '--label', + 'U-Boot token', '--pin', '1111', + '--so-pin', '222222') + softhsm2_util.run_cmd('--import', self.TestFile('dev.key'), + '--token', 'U-Boot token', '--label', + 'test_key', '--id', '999999', '--pin', '1111') + + return softhsm2_conf + + def _CheckPreLoadEngine(self, dts, softhsm2_conf, padding): + """Sign an image through the pkcs11 engine and check the signature + + Args: + dts (str): Filename of the device tree to build + softhsm2_conf (str): Filename of the SoftHSM configuration file + padding (str): Padding used by the device tree + """ + ossl_conf = self.TestFile('fit/openssl.conf') + with unittest.mock.patch.dict('os.environ', + {'OPENSSL_CONF': ossl_conf, + 'SOFTHSM2_CONF': softhsm2_conf}): + data = self._DoReadFile(dts) + + image_fname = tools.get_output_filename('image.bin') + is_signed = self._CheckPreload(image_fname, self.TestFile('dev.key'), + padding=padding) + + 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 testPreLoadEnginePkcs11(self): + """Test a pre-load header signed through the pkcs11 OpenSSL engine""" + softhsm2_conf = self._SetupPreLoadEngine('testPreLoadEnginePkcs11.') + self._CheckPreLoadEngine('security/pre_load_engine_pkcs11.dts', + softhsm2_conf, 'pkcs-1.5') + + def testPreLoadEnginePkcs11Pss(self): + """Test a pre-load header signed through the engine with pss padding""" + softhsm2_conf = self._SetupPreLoadEngine('testPreLoadEnginePkcs11Pss.') + self._CheckPreLoadEngine('security/pre_load_engine_pkcs11_pss.dts', + softhsm2_conf, 'pss') + + def testPreLoadEngineMissingOpenssl(self): + """Test that a missing openssl is reported when using an engine""" + with terminal.capture() as (_, stderr): + self._DoTestFile('security/pre_load_engine_pkcs11.dts', + force_missing_bintools='openssl') + err = stderr.getvalue() + self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl") + 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_engine_pkcs11.dts b/tools/binman/test/security/pre_load_engine_pkcs11.dts new file mode 100644 index 00000000000..468dd30059b --- /dev/null +++ b/tools/binman/test/security/pre_load_engine_pkcs11.dts @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + pre-load { + content = <&image>; + algo-name = "sha256,rsa2048"; + padding-name = "pkcs-1.5"; + key-name = "test_key"; + engine = "pkcs11"; + header-size = <4096>; + version = <0x11223344>; + }; + + image: blob-ext { + filename = "refcode.bin"; + }; + }; +}; diff --git a/tools/binman/test/security/pre_load_engine_pkcs11_pss.dts b/tools/binman/test/security/pre_load_engine_pkcs11_pss.dts new file mode 100644 index 00000000000..4e09e97cb09 --- /dev/null +++ b/tools/binman/test/security/pre_load_engine_pkcs11_pss.dts @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + pre-load { + content = <&image>; + algo-name = "sha256,rsa2048"; + padding-name = "pss"; + key-name = "test_key"; + engine = "pkcs11"; + header-size = <4096>; + version = <0x11223344>; + }; + + image: blob-ext { + filename = "refcode.bin"; + }; + }; +}; -- 2.55.0
