[U-Boot] [PATCH 26/31] binman: Support hashing entries

Simon Glass sjg at chromium.org
Fri Sep 14 10:57:31 UTC 2018


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 at chromium.org>
---

 tools/binman/README                    | 22 ++++++++++++++++
 tools/binman/bsection.py               |  3 +++
 tools/binman/entry.py                  |  4 +++
 tools/binman/ftest.py                  | 36 ++++++++++++++++++++++++++
 tools/binman/state.py                  | 25 ++++++++++++++++++
 tools/binman/test/90_hash.dts          | 12 +++++++++
 tools/binman/test/91_hash_no_algo.dts  | 11 ++++++++
 tools/binman/test/92_hash_bad_algo.dts | 12 +++++++++
 tools/binman/test/99_hash_section.dts  | 18 +++++++++++++
 9 files changed, 143 insertions(+)
 create mode 100644 tools/binman/test/90_hash.dts
 create mode 100644 tools/binman/test/91_hash_no_algo.dts
 create mode 100644 tools/binman/test/92_hash_bad_algo.dts
 create mode 100644 tools/binman/test/99_hash_section.dts

diff --git a/tools/binman/README b/tools/binman/README
index 7e566ffe05b..6bdb7e4c66e 100644
--- a/tools/binman/README
+++ b/tools/binman/README
@@ -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
 -----------------------
 
diff --git a/tools/binman/bsection.py b/tools/binman/bsection.py
index 52ac31a4672..650e9ba353f 100644
--- a/tools/binman/bsection.py
+++ b/tools/binman/bsection.py
@@ -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()
 
diff --git a/tools/binman/entry.py b/tools/binman/entry.py
index 0915b470b4e..fd7223477eb 100644
--- a/tools/binman/entry.py
+++ b/tools/binman/entry.py
@@ -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
diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index faacb6fa8f6..6c86f4a742c 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -6,6 +6,7 @@
 #
 #    python -m unittest func_test.TestFunctional.testHelp
 
+import hashlib
 import lz4
 from optparse import OptionParser
 import os
@@ -1609,6 +1610,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()
diff --git a/tools/binman/state.py b/tools/binman/state.py
index 2f8c0863a8f..d945e4bf657 100644
--- a/tools/binman/state.py
+++ b/tools/binman/state.py
@@ -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
index 00000000000..200304599dc
--- /dev/null
+++ b/tools/binman/test/90_hash.dts
@@ -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
index 00000000000..b64df205117
--- /dev/null
+++ b/tools/binman/test/91_hash_no_algo.dts
@@ -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
index 00000000000..d2402000db6
--- /dev/null
+++ b/tools/binman/test/92_hash_bad_algo.dts
@@ -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
index 00000000000..dcd8683d642
--- /dev/null
+++ b/tools/binman/test/99_hash_section.dts
@@ -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";
+			};
+		};
+	};
+};
-- 
2.19.0.397.gdd90340f6a-goog



More information about the U-Boot mailing list