]> git.ipfire.org Git - thirdparty/u-boot.git/commitdiff
binman: Support hashing entries
authorSimon Glass <sjg@chromium.org>
Fri, 14 Sep 2018 10:57:31 +0000 (04:57 -0600)
committerSimon Glass <sjg@chromium.org>
Sat, 29 Sep 2018 17:49:35 +0000 (11:49 -0600)
Sometimesi it us useful to be able to verify the content of entries with
a hash. Add an easy way to do this in binman. The hash information can be
retrieved from the device tree at run time.

Signed-off-by: Simon Glass <sjg@chromium.org>
tools/binman/README
tools/binman/bsection.py
tools/binman/entry.py
tools/binman/ftest.py
tools/binman/state.py
tools/binman/test/90_hash.dts [new file with mode: 0644]
tools/binman/test/91_hash_no_algo.dts [new file with mode: 0644]
tools/binman/test/92_hash_bad_algo.dts [new file with mode: 0644]
tools/binman/test/99_hash_section.dts [new file with mode: 0644]

index cf1a06d164da0f0a08112005a4f03300d5f6511c..088f3a63d9c19a0562e2a387440910d6e30ac067 100644 (file)
@@ -466,6 +466,28 @@ see README.entries. This is generated from the source code using:
        binman -E >tools/binman/README.entries
 
 
+Hashing Entries
+---------------
+
+It is possible to ask binman to hash the contents of an entry and write that
+value back to the device-tree node. For example:
+
+       binman {
+               u-boot {
+                       hash {
+                               algo = "sha256";
+                       };
+               };
+       };
+
+Here, a new 'value' property will be written to the 'hash' node containing
+the hash of the 'u-boot' entry. Only SHA256 is supported at present. Whole
+sections can be hased if desired, by adding the 'hash' node to the section.
+
+The has value can be chcked at runtime by hashing the data actually read and
+comparing this has to the value in the device tree.
+
+
 Order of image creation
 -----------------------
 
index 52ac31a4672ea8ffb678942cdc53a84e22f1d0e7..650e9ba353fb95186480bdd411b6df6526478c98 100644 (file)
@@ -89,6 +89,8 @@ class Section(object):
 
     def _ReadEntries(self):
         for node in self._node.subnodes:
+            if node.name == 'hash':
+                continue
             entry = Entry.Create(self, node)
             entry.SetPrefix(self._name_prefix)
             self._entries[node.name] = entry
@@ -112,6 +114,7 @@ class Section(object):
         for prop in ['offset', 'size', 'image-pos']:
             if not prop in self._node.props:
                 state.AddZeroProp(self._node, prop)
+        state.CheckAddHashProp(self._node)
         for entry in self._entries.values():
             entry.AddMissingProperties()
 
index 0915b470b4e93cee9cdc24337189bfb113a53579..fd7223477eb02bbb142b8f50ff75245bf9573062 100644 (file)
@@ -189,12 +189,16 @@ class Entry(object):
         for prop in ['offset', 'size', 'image-pos']:
             if not prop in self._node.props:
                 state.AddZeroProp(self._node, prop)
+        err = state.CheckAddHashProp(self._node)
+        if err:
+            self.Raise(err)
 
     def SetCalculatedProperties(self):
         """Set the value of device-tree properties calculated by binman"""
         state.SetInt(self._node, 'offset', self.offset)
         state.SetInt(self._node, 'size', self.size)
         state.SetInt(self._node, 'image-pos', self.image_pos)
+        state.CheckSetHashValue(self._node, self.GetData)
 
     def ProcessFdt(self, fdt):
         """Allow entries to adjust the device tree
index b1569433234b00e9ee68fb9fe7b68082635e6c36..c46a065382703d5546f06834b7a1b07755a9b9dd 100644 (file)
@@ -6,6 +6,7 @@
 #
 #    python -m unittest func_test.TestFunctional.testHelp
 
+import hashlib
 from optparse import OptionParser
 import os
 import shutil
@@ -1608,6 +1609,41 @@ class TestFunctional(unittest.TestCase):
         self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
                       'expanding entry', str(e.exception))
 
+    def testHash(self):
+        """Test hashing of the contents of an entry"""
+        _, _, _, out_dtb_fname = self._DoReadFileDtb('90_hash.dts',
+                use_real_dtb=True, update_dtb=True)
+        dtb = fdt.Fdt(out_dtb_fname)
+        dtb.Scan()
+        hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
+        m = hashlib.sha256()
+        m.update(U_BOOT_DATA)
+        self.assertEqual(m.digest(), ''.join(hash_node.value))
+
+    def testHashNoAlgo(self):
+        with self.assertRaises(ValueError) as e:
+            self._DoReadFileDtb('91_hash_no_algo.dts', update_dtb=True)
+        self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
+                      'hash node', str(e.exception))
+
+    def testHashBadAlgo(self):
+        with self.assertRaises(ValueError) as e:
+            self._DoReadFileDtb('92_hash_bad_algo.dts', update_dtb=True)
+        self.assertIn("Node '/binman/u-boot': Unknown hash algorithm",
+                      str(e.exception))
+
+    def testHashSection(self):
+        """Test hashing of the contents of an entry"""
+        _, _, _, out_dtb_fname = self._DoReadFileDtb('99_hash_section.dts',
+                use_real_dtb=True, update_dtb=True)
+        dtb = fdt.Fdt(out_dtb_fname)
+        dtb.Scan()
+        hash_node = dtb.GetNode('/binman/section/hash').props['value']
+        m = hashlib.sha256()
+        m.update(U_BOOT_DATA)
+        m.update(16 * 'a')
+        self.assertEqual(m.digest(), ''.join(hash_node.value))
+
 
 if __name__ == "__main__":
     unittest.main()
index 2f8c0863a8f24838443b1dbb4b76a871100a8272..d945e4bf6576f2d316d81c1f9d0482c5fdaf5604 100644 (file)
@@ -5,6 +5,7 @@
 # Holds and modifies the state information held by binman
 #
 
+import hashlib
 import re
 from sets import Set
 
@@ -226,3 +227,27 @@ def SetInt(node, prop, value):
     """
     for n in GetUpdateNodes(node):
         n.SetInt(prop, value)
+
+def CheckAddHashProp(node):
+    hash_node = node.FindNode('hash')
+    if hash_node:
+        algo = hash_node.props.get('algo')
+        if not algo:
+            return "Missing 'algo' property for hash node"
+        if algo.value == 'sha256':
+            size = 32
+        else:
+            return "Unknown hash algorithm '%s'" % algo
+        for n in GetUpdateNodes(hash_node):
+            n.AddEmptyProp('value', size)
+
+def CheckSetHashValue(node, get_data_func):
+    hash_node = node.FindNode('hash')
+    if hash_node:
+        algo = hash_node.props.get('algo').value
+        if algo == 'sha256':
+            m = hashlib.sha256()
+            m.update(get_data_func())
+            data = m.digest()
+        for n in GetUpdateNodes(hash_node):
+            n.SetData('value', data)
diff --git a/tools/binman/test/90_hash.dts b/tools/binman/test/90_hash.dts
new file mode 100644 (file)
index 0000000..2003045
--- /dev/null
@@ -0,0 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0+
+/dts-v1/;
+
+/ {
+       binman {
+               u-boot {
+                       hash {
+                               algo = "sha256";
+                       };
+               };
+       };
+};
diff --git a/tools/binman/test/91_hash_no_algo.dts b/tools/binman/test/91_hash_no_algo.dts
new file mode 100644 (file)
index 0000000..b64df20
--- /dev/null
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0+
+/dts-v1/;
+
+/ {
+       binman {
+               u-boot {
+                       hash {
+                       };
+               };
+       };
+};
diff --git a/tools/binman/test/92_hash_bad_algo.dts b/tools/binman/test/92_hash_bad_algo.dts
new file mode 100644 (file)
index 0000000..d240200
--- /dev/null
@@ -0,0 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0+
+/dts-v1/;
+
+/ {
+       binman {
+               u-boot {
+                       hash {
+                               algo = "invalid";
+                       };
+               };
+       };
+};
diff --git a/tools/binman/test/99_hash_section.dts b/tools/binman/test/99_hash_section.dts
new file mode 100644 (file)
index 0000000..dcd8683
--- /dev/null
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: GPL-2.0+
+/dts-v1/;
+
+/ {
+       binman {
+               section {
+                       u-boot {
+                       };
+                       fill {
+                               size = <0x10>;
+                               fill-byte = [61];
+                       };
+                       hash {
+                               algo = "sha256";
+                       };
+               };
+       };
+};