Add end-to-end functional test for HSM-based signing of pre-load headers. The test verifies that binman can use PKCS#11 libraries to sign data via hardware security modules and can generate pre-load headers with HSM signatures.
Signed-off-by: Yan WANG <[email protected]> --- tools/binman/ftest.py | 76 +++++++++++++++++++ .../security/pre_load_default_padding.dts | 23 ++++++ .../security/pre_load_hsm_invalid_padding.dts | 27 +++++++ .../security/pre_load_hsm_missing_library.dts | 27 +++++++ .../security/pre_load_hsm_missing_tool.dts | 27 +++++++ .../security/pre_load_missing_key_name.dts | 23 ++++++ 6 files changed, 203 insertions(+) create mode 100644 tools/binman/test/security/pre_load_default_padding.dts create mode 100644 tools/binman/test/security/pre_load_hsm_invalid_padding.dts create mode 100644 tools/binman/test/security/pre_load_hsm_missing_library.dts create mode 100644 tools/binman/test/security/pre_load_hsm_missing_tool.dts create mode 100644 tools/binman/test/security/pre_load_missing_key_name.dts diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py index 329b91dfd06..e76a8042f4c 100644 --- a/tools/binman/ftest.py +++ b/tools/binman/ftest.py @@ -5994,6 +5994,82 @@ 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 testPreLoadHsmMissingLibrary(self): + """Test HSM signing with missing hsm-library property""" + with self.assertRaises(ValueError) as exc: + self._DoReadFile('security/pre_load_hsm_missing_library.dts') + self.assertIn('hsm-library is required for HSM signing', + str(exc.exception)) + + def testPreLoadHsmInvalidPadding(self): + """Test HSM signing with invalid padding""" + with self.assertRaises(ValueError) as exc: + self._DoReadFile('security/pre_load_hsm_invalid_padding.dts') + self.assertIn('Unsupported padding scheme', str(exc.exception)) + + def testPreLoadHsmMissingTool(self): + """Test HSM signing when pkcs11_tool is not available""" + try: + with self.assertRaises(ValueError) as exc: + self._DoTestFile('security/pre_load_hsm_missing_tool.dts', + force_missing_bintools='pkcs11-tool') + self.assertIn('pkcs11-tool btool not available', str(exc.exception)) + finally: + bintool.Bintool.set_missing_list(None) + + def testPreLoadHsmSignError(self): + """Test HSM signing with pkcs11-tool ValueError""" + from binman.btool import pkcs11_tool + + def mock_sign_value_error(*args, **kwargs): + raise ValueError("Mock HSM error") + + with unittest.mock.patch.object(pkcs11_tool.Bintoolpkcs11_tool, 'is_present', + return_value=True): + with unittest.mock.patch.object(pkcs11_tool.Bintoolpkcs11_tool, 'sign', + side_effect=mock_sign_value_error): + with self.assertRaises(ValueError) as exc: + self._DoReadFile('security/pre_load_hsm_missing_tool.dts') + self.assertIn('HSM signing failed', str(exc.exception)) + + def testPreLoadHsmSignRuntimeError(self): + """Test HSM signing with pkcs11-tool RuntimeError""" + from binman.btool import pkcs11_tool + + def mock_sign_runtime_error(*args, **kwargs): + raise RuntimeError("Mock HSM runtime error") + + with unittest.mock.patch.object(pkcs11_tool.Bintoolpkcs11_tool, 'is_present', + return_value=True): + with unittest.mock.patch.object(pkcs11_tool.Bintoolpkcs11_tool, 'sign', + side_effect=mock_sign_runtime_error): + with self.assertRaises(ValueError) as exc: + self._DoReadFile('security/pre_load_hsm_missing_tool.dts') + self.assertIn('HSM signing failed', str(exc.exception)) + + def testPreLoadMissingKeyName(self): + """Test file-based signing with missing key-name property""" + entry_args = { + 'pre-load-key-path': os.path.join(self._binman_dir, 'test'), + } + with self.assertRaises(ValueError) as exc: + self._DoReadFileDtb('security/pre_load_missing_key_name.dts', + entry_args=entry_args) + self.assertIn('key-name is required for file-based signing', + str(exc.exception)) + + def testPreLoadDefaultPadding(self): + """Test pre-load with no padding-name (should default to pkcs-1.5)""" + entry_args = { + 'pre-load-key-path': os.path.join(self._binman_dir, 'test'), + } + data = self._DoReadFileDtb('security/pre_load_default_padding.dts', + entry_args=entry_args, + extra_indirs=[os.path.join(self._binman_dir, 'test')])[0] + 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)]) + def _CheckSafeUniqueNames(self, *images): """Check all entries of given images for unsafe unique names""" diff --git a/tools/binman/test/security/pre_load_default_padding.dts b/tools/binman/test/security/pre_load_default_padding.dts new file mode 100644 index 00000000000..2263df72a25 --- /dev/null +++ b/tools/binman/test/security/pre_load_default_padding.dts @@ -0,0 +1,23 @@ +// 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 intentionally omitted to test default */ + key-name = "dev.key"; + header-size = <4096>; + version = <0x11223344>; + }; + + image: blob-ext { + filename = "refcode.bin"; + }; + }; +}; diff --git a/tools/binman/test/security/pre_load_hsm_invalid_padding.dts b/tools/binman/test/security/pre_load_hsm_invalid_padding.dts new file mode 100644 index 00000000000..3e735e545a9 --- /dev/null +++ b/tools/binman/test/security/pre_load_hsm_invalid_padding.dts @@ -0,0 +1,27 @@ +// 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 = "invalid-padding"; + header-size = <4096>; + version = <1>; + hsm-support; + hsm-library = "/usr/lib/softhsm/libsofthsm2.so"; + hsm-token-label = "uboot-hsm"; + hsm-key-label = "uboot-key"; + hsm-pin = "1234"; + }; + + image: blob-ext { + filename = "refcode.bin"; + }; + }; +}; diff --git a/tools/binman/test/security/pre_load_hsm_missing_library.dts b/tools/binman/test/security/pre_load_hsm_missing_library.dts new file mode 100644 index 00000000000..34dfd16c163 --- /dev/null +++ b/tools/binman/test/security/pre_load_hsm_missing_library.dts @@ -0,0 +1,27 @@ +// 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"; + header-size = <4096>; + version = <0x11223344>; + hsm-support; + /* hsm-library intentionally missing to test error */ + hsm-token-label = "uboot-hsm"; + hsm-key-label = "uboot-key"; + hsm-pin = "1234"; + }; + + image: blob-ext { + filename = "refcode.bin"; + }; + }; +}; diff --git a/tools/binman/test/security/pre_load_hsm_missing_tool.dts b/tools/binman/test/security/pre_load_hsm_missing_tool.dts new file mode 100644 index 00000000000..451429688fe --- /dev/null +++ b/tools/binman/test/security/pre_load_hsm_missing_tool.dts @@ -0,0 +1,27 @@ +// 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"; + 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: blob-ext { + filename = "refcode.bin"; + }; + }; +}; diff --git a/tools/binman/test/security/pre_load_missing_key_name.dts b/tools/binman/test/security/pre_load_missing_key_name.dts new file mode 100644 index 00000000000..b83fa817b0b --- /dev/null +++ b/tools/binman/test/security/pre_load_missing_key_name.dts @@ -0,0 +1,23 @@ +// 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 intentionally missing for file-based signing */ + header-size = <4096>; + version = <1>; + }; + + image: blob-ext { + filename = "refcode.bin"; + }; + }; +}; -- 2.43.0
