]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
binman: Add an entry for a Chromium vblock
authorSimon Glass <sjg@chromium.org>
Tue, 17 Jul 2018 19:25:47 +0000 (13:25 -0600)
committerSimon Glass <sjg@chromium.org>
Wed, 1 Aug 2018 22:30:48 +0000 (16:30 -0600)
This adds support for a Chromium verified boot block, used to sign a
read-write section of the image.

Signed-off-by: Simon Glass <sjg@chromium.org>
tools/binman/README.entries
tools/binman/bsection.py
tools/binman/entry.py
tools/binman/etype/vblock.py [new file with mode: 0644]
tools/binman/ftest.py
tools/binman/test/74_vblock.dts [new file with mode: 0644]
tools/binman/test/75_vblock_no_content.dts [new file with mode: 0644]
tools/binman/test/76_vblock_bad_phandle.dts [new file with mode: 0644]
tools/binman/test/77_vblock_bad_entry.dts [new file with mode: 0644]

index 41b70192c087134af0e036c9900a9e777ef3cf97..1b75ca005257079ba5e06c4b207ff6cc3add14a4 100644 (file)
@@ -496,6 +496,23 @@ complicated. Otherwise it is the same as the u_boot entry.
 
 
 
+Entry: vblock: An entry which contains a Chromium OS verified boot block
+------------------------------------------------------------------------
+
+Properties / Entry arguments:
+    - keydir: Directory containing the public keys to use
+    - keyblock: Name of the key file to use (inside keydir)
+    - signprivate: Name of provide key file to use (inside keydir)
+    - version: Version number of the vblock (typically 1)
+    - kernelkey: Name of the kernel key to use (inside keydir)
+    - preamble-flags: Value of the vboot preamble flags (typically 0)
+
+Chromium OS  signs the read-write firmware and kernel, writing the signature
+in this block. This allows U-Boot to verify that the next firmware stage
+and kernel are genuine.
+
+
+
 Entry: x86-start16: x86 16-bit start-up code for U-Boot
 -------------------------------------------------------
 
index 08c6f0cda856191a358336a12ef2da223478dcde..70a6ec17760931549ffbd79ebe6d4365b3679621 100644 (file)
@@ -381,3 +381,27 @@ class Section(object):
         Entry.WriteMapLine(fd, indent, self._name, self._offset, self._size)
         for entry in self._entries.values():
             entry.WriteMap(fd, indent + 1)
+
+    def GetContentsByPhandle(self, phandle, source_entry):
+        """Get the data contents of an entry specified by a phandle
+
+        This uses a phandle to look up a node and and find the entry
+        associated with it. Then it returnst he contents of that entry.
+
+        Args:
+            phandle: Phandle to look up (integer)
+            source_entry: Entry containing that phandle (used for error
+                reporting)
+
+        Returns:
+            data from associated entry (as a string), or None if not found
+        """
+        node = self._node.GetFdt().LookupPhandle(phandle)
+        if not node:
+            source_entry.Raise("Cannot find node for phandle %d" % phandle)
+        for entry in self._entries.values():
+            if entry._node == node:
+                if entry.data is None:
+                    return None
+                return entry.data
+        source_entry.Raise("Cannot find entry for node '%s'" % node.name)
index 8b910feff60ab4980dfd90dbb80906b277870312..996f03e3a68d70e9f8e54327b71d853c40af2f24 100644 (file)
@@ -65,7 +65,7 @@ class Entry(object):
         self.name = node and (name_prefix + node.name) or 'none'
         self.offset = None
         self.size = None
-        self.data = ''
+        self.data = None
         self.contents_size = 0
         self.align = None
         self.align_size = None
diff --git a/tools/binman/etype/vblock.py b/tools/binman/etype/vblock.py
new file mode 100644 (file)
index 0000000..595af54
--- /dev/null
@@ -0,0 +1,74 @@
+# SPDX-License-Identifier: GPL-2.0+
+# Copyright (c) 2018 Google, Inc
+# Written by Simon Glass <sjg@chromium.org>
+#
+
+# Support for a Chromium OS verified boot block, used to sign a read-write
+# section of the image.
+
+from collections import OrderedDict
+import os
+
+from entry import Entry, EntryArg
+
+import fdt_util
+import tools
+
+class Entry_vblock(Entry):
+    """An entry which contains a Chromium OS verified boot block
+
+    Properties / Entry arguments:
+        - keydir: Directory containing the public keys to use
+        - keyblock: Name of the key file to use (inside keydir)
+        - signprivate: Name of provide key file to use (inside keydir)
+        - version: Version number of the vblock (typically 1)
+        - kernelkey: Name of the kernel key to use (inside keydir)
+        - preamble-flags: Value of the vboot preamble flags (typically 0)
+
+    Chromium OS signs the read-write firmware and kernel, writing the signature
+    in this block. This allows U-Boot to verify that the next firmware stage
+    and kernel are genuine.
+    """
+    def __init__(self, section, etype, node):
+        Entry.__init__(self, section, etype, node)
+        self.content = fdt_util.GetPhandleList(self._node, 'content')
+        if not self.content:
+            self.Raise("Vblock must have a 'content' property")
+        (self.keydir, self.keyblock, self.signprivate, self.version,
+         self.kernelkey, self.preamble_flags) = self.GetEntryArgsOrProps([
+            EntryArg('keydir', str),
+            EntryArg('keyblock', str),
+            EntryArg('signprivate', str),
+            EntryArg('version', int),
+            EntryArg('kernelkey', str),
+            EntryArg('preamble-flags', int)])
+
+    def ObtainContents(self):
+        # Join up the data files to be signed
+        input_data = ''
+        for entry_phandle in self.content:
+            data = self.section.GetContentsByPhandle(entry_phandle, self)
+            if data is None:
+                # Data not available yet
+                return False
+            input_data += data
+
+        output_fname = tools.GetOutputFilename('vblock.%s' % self.name)
+        input_fname = tools.GetOutputFilename('input.%s' % self.name)
+        tools.WriteFile(input_fname, input_data)
+        prefix = self.keydir + '/'
+        args = [
+            'vbutil_firmware',
+            '--vblock', output_fname,
+            '--keyblock', prefix + self.keyblock,
+            '--signprivate', prefix + self.signprivate,
+            '--version', '%d' % self.version,
+            '--fv', input_fname,
+            '--kernelkey', prefix + self.kernelkey,
+            '--flags', '%d' % self.preamble_flags,
+        ]
+        #out.Notice("Sign '%s' into %s" % (', '.join(self.value), self.label))
+        stdout = tools.Run('futility', *args)
+        #out.Debug(stdout)
+        self.SetContents(tools.ReadFile(output_fname))
+        return True
index f15b215c60891e9f10763a635067a9eb04579e6f..a6de4cb93b8afe06061ba000e6126db313124a3f 100644 (file)
@@ -49,6 +49,7 @@ TEXT_DATA3            = 'text3'
 CROS_EC_RW_DATA       = 'ecrw'
 GBB_DATA              = 'gbbd'
 BMPBLK_DATA           = 'bmp'
+VBLOCK_DATA           = 'vblk'
 
 
 class TestFunctional(unittest.TestCase):
@@ -1304,6 +1305,46 @@ class TestFunctional(unittest.TestCase):
         self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
                       str(e.exception))
 
+    def _HandleVblockCommand(self, pipe_list):
+        """Fake calls to the futility utility"""
+        if pipe_list[0][0] == 'futility':
+            fname = pipe_list[0][3]
+            with open(fname, 'w') as fd:
+                fd.write(VBLOCK_DATA)
+            return command.CommandResult()
+
+    def testVblock(self):
+        """Test for the Chromium OS Verified Boot Block"""
+        command.test_result = self._HandleVblockCommand
+        entry_args = {
+            'keydir': 'devkeys',
+        }
+        data, _, _, _ = self._DoReadFileDtb('74_vblock.dts',
+                                            entry_args=entry_args)
+        expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
+        self.assertEqual(expected, data)
+
+    def testVblockNoContent(self):
+        """Test we detect a vblock which has no content to sign"""
+        with self.assertRaises(ValueError) as e:
+            self._DoReadFile('75_vblock_no_content.dts')
+        self.assertIn("Node '/binman/vblock': Vblock must have a 'content' "
+                      'property', str(e.exception))
+
+    def testVblockBadPhandle(self):
+        """Test that we detect a vblock with an invalid phandle in contents"""
+        with self.assertRaises(ValueError) as e:
+            self._DoReadFile('76_vblock_bad_phandle.dts')
+        self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
+                      '1000', str(e.exception))
+
+    def testVblockBadEntry(self):
+        """Test that we detect an entry that points to a non-entry"""
+        with self.assertRaises(ValueError) as e:
+            self._DoReadFile('77_vblock_bad_entry.dts')
+        self.assertIn("Node '/binman/vblock': Cannot find entry for node "
+                      "'other'", str(e.exception))
+
 
 if __name__ == "__main__":
     unittest.main()
diff --git a/tools/binman/test/74_vblock.dts b/tools/binman/test/74_vblock.dts
new file mode 100644 (file)
index 0000000..f0c21bf
--- /dev/null
@@ -0,0 +1,28 @@
+// SPDX-License-Identifier: GPL-2.0+
+/dts-v1/;
+
+/ {
+       #address-cells = <1>;
+       #size-cells = <1>;
+
+       binman {
+               u_boot: u-boot {
+               };
+
+               vblock {
+                       content = <&u_boot &dtb>;
+                       keyblock = "firmware.keyblock";
+                       signprivate = "firmware_data_key.vbprivk";
+                       version = <1>;
+                       kernelkey = "kernel_subkey.vbpubk";
+                       preamble-flags = <1>;
+               };
+
+               /*
+                * Put this after the vblock so that its contents are not
+                * available when the vblock first tries to obtain its contents
+                */
+               dtb: u-boot-dtb {
+               };
+       };
+};
diff --git a/tools/binman/test/75_vblock_no_content.dts b/tools/binman/test/75_vblock_no_content.dts
new file mode 100644 (file)
index 0000000..676d947
--- /dev/null
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: GPL-2.0+
+/dts-v1/;
+
+/ {
+       #address-cells = <1>;
+       #size-cells = <1>;
+
+       binman {
+               u_boot: u-boot {
+               };
+
+               vblock {
+                       keyblock = "firmware.keyblock";
+                       signprivate = "firmware_data_key.vbprivk";
+                       version = <1>;
+                       kernelkey = "kernel_subkey.vbpubk";
+                       preamble-flags = <1>;
+               };
+
+               dtb: u-boot-dtb {
+               };
+       };
+};
diff --git a/tools/binman/test/76_vblock_bad_phandle.dts b/tools/binman/test/76_vblock_bad_phandle.dts
new file mode 100644 (file)
index 0000000..ffbd0c3
--- /dev/null
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: GPL-2.0+
+/dts-v1/;
+
+/ {
+       #address-cells = <1>;
+       #size-cells = <1>;
+
+       binman {
+               u_boot: u-boot {
+               };
+
+               vblock {
+                       content = <1000>;
+                       keyblock = "firmware.keyblock";
+                       signprivate = "firmware_data_key.vbprivk";
+                       version = <1>;
+                       kernelkey = "kernel_subkey.vbpubk";
+                       preamble-flags = <1>;
+               };
+
+               dtb: u-boot-dtb {
+               };
+       };
+};
diff --git a/tools/binman/test/77_vblock_bad_entry.dts b/tools/binman/test/77_vblock_bad_entry.dts
new file mode 100644 (file)
index 0000000..764c42a
--- /dev/null
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: GPL-2.0+
+/dts-v1/;
+
+/ {
+       #address-cells = <1>;
+       #size-cells = <1>;
+
+       binman {
+               u_boot: u-boot {
+               };
+
+               vblock {
+                       content = <&u_boot &other>;
+                       keyblock = "firmware.keyblock";
+                       signprivate = "firmware_data_key.vbprivk";
+                       version = <1>;
+                       kernelkey = "kernel_subkey.vbpubk";
+                       preamble-flags = <1>;
+               };
+
+               dtb: u-boot-dtb {
+               };
+       };
+
+       other: other {
+       };
+};