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

Reply via email to