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

Reply via email to