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

Reply via email to