_CreateHeader() signs twice, once for the image and once for the first
header, with the same key and padding. Move the signing into a _sign()
helper rather than repeating it.

This is a preparation for signing with an OpenSSL engine, which needs a
second implementation of _sign().

Adjust testPreLoadInvalidKey() test to verify that signing is never
attempted for a key with the wrong size.

Signed-off-by: Lorenz Kofler <[email protected]>
---
Changes in v2:
- Move the invalid-key test change into this patch to verify
  that signing is not attempted for a key with the wrong size.

 tools/binman/etype/pre_load.py | 49 +++++++++++++++++++++-------------
 tools/binman/ftest.py          | 12 ++++++---
 2 files changed, 39 insertions(+), 22 deletions(-)

diff --git a/tools/binman/etype/pre_load.py b/tools/binman/etype/pre_load.py
index 0d953cb258e..0cf635ab23a 100644
--- a/tools/binman/etype/pre_load.py
+++ b/tools/binman/etype/pre_load.py
@@ -86,6 +86,31 @@ def ReadNode(self):
         if self.key_path is None:
             self.key_path = ''
 
+    def _sign(self, data, key, hash_name, padding_name):
+        """Sign data with a key
+
+        Args:
+            data (bytes): Data to sign
+            key (RsaKey): Key to sign with
+            hash_name (str): Hash algorithm to use
+            padding_name (str): Padding to use
+
+        Returns:
+            bytes: Signature
+        """
+        hash_data = SHAS[hash_name].new()
+        hash_data.update(data)
+
+        if padding_name == "pss":
+            salt_len = key.size_in_bytes() - hash_data.digest_size - 2
+            padding = pss
+            padding_args = {'salt_bytes': salt_len}
+        else:
+            padding = pkcs1_15
+            padding_args = {}
+
+        return padding.new(key, **padding_args).sign(hash_data)
+
     def _CreateHeader(self):
         """Create a pre load header"""
         hash_name, sign_name = self.algo_name.split(',')
@@ -105,26 +130,13 @@ def _CreateHeader(self):
         if key.size_in_bytes() != RSAS[sign_name]:
             self.Raise("The key " + self.key_name + " don't have the expected 
size")
 
-        # Compute the hash
-        hash_image = SHAS[hash_name].new()
-        hash_image.update(self.image)
-
-        # Compute the signature
         if padding_name is None:
             padding_name = "pkcs-1.5"
-        padding = None
-        padding_args = None
-        if padding_name == "pss":
-            salt_len = key.size_in_bytes() - hash_image.digest_size - 2
-            padding = pss
-            padding_args = {'salt_bytes': salt_len}
-        elif padding_name == "pkcs-1.5":
-            padding = pkcs1_15
-            padding_args = {}
-        else:
+        if padding_name not in ("pss", "pkcs-1.5"):
             self.Raise(padding_name + " is not supported")
 
-        sig = padding.new(key, **padding_args).sign(hash_image)
+        # Compute the signature
+        sig = self._sign(self.image, key, hash_name, padding_name)
 
         hash_sig = SHA256.new()
         hash_sig.update(sig)
@@ -142,9 +154,8 @@ def _CreateHeader(self):
                                    ofs_img_sig, flags, reserved0,
                                    reserved1, hash_sig.digest())
 
-        hash_first_header = SHAS[hash_name].new()
-        hash_first_header.update(first_header)
-        sig_first_header = padding.new(key, 
**padding_args).sign(hash_first_header)
+        sig_first_header = self._sign(first_header, key, hash_name,
+                                      padding_name)
 
         data = first_header + sig_first_header + sig
         pad  = bytearray(self.header_size - len(data))
diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index 2fb452b4e46..4002f6837f4 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -5903,12 +5903,18 @@ def testPreLoadInvalidAlgo(self):
 
     def testPreLoadInvalidKey(self):
         """Test an image with a pre-load header with an invalid key"""
+        from binman.etype import pre_load
+
         entry_args = {
             'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
         }
-        with self.assertRaises(ValueError) as e:
-            data = self._DoReadFileDtb('security/pre_load_invalid_key.dts',
-                                       entry_args=entry_args)
+        with unittest.mock.patch.object(
+                pre_load.Entry_pre_load, '_sign',
+                side_effect=AssertionError('signing should not be attempted')):
+            with self.assertRaisesRegex(ValueError,
+                                        "don't have the expected size"):
+                self._DoReadFileDtb('security/pre_load_invalid_key.dts',
+                                    entry_args=entry_args)
 
     def testPreLoadEncryptedFit(self):
         """Test an encrypted FIT image with a pre-load header"""
-- 
2.55.0

Reply via email to