cros_bundle_firmware: directly add vblocks to cb_with_fmap

Now that we're sure that cb_with_fmap (the template used for packing)
already contains the right CBFS regions, sign them, too.

BUG=chromium:595715
BRANCH=none
TEST=With CL:397623 also applied, verify bit-equivalence of regions
between image.bin and cb_with_fmap with CL:397219 or similar.

Change-Id: Ia8af2614215b73c6ebdd580faad8c821d9c9b27b
Signed-off-by: Patrick Georgi <pgeorgi@google.com>
Reviewed-on: https://chromium-review.googlesource.com/397218
Commit-Ready: Patrick Georgi <pgeorgi@chromium.org>
Tested-by: Patrick Georgi <pgeorgi@chromium.org>
Reviewed-by: Randall Spangler <rspangler@chromium.org>
diff --git a/host/lib/bundle_firmware.py b/host/lib/bundle_firmware.py
index 67e3acb..b4edc64 100644
--- a/host/lib/bundle_firmware.py
+++ b/host/lib/bundle_firmware.py
@@ -824,6 +824,60 @@
     for blob_type in blob_list:
       self._BuildBlob(pack, fdt, blob_type)
 
+  def _BuildKeyblocks(self, pack):
+    """Compute vblocks and write them into their FMAP regions.
+       Works for the (VBLOCK_?,FW_MAIN_?) pairs
+    """
+    cb_copy = pack.GetProperty('cb_with_fmap')
+    fmap_blob = open(self.coreboot_fname).read()
+    f = fmap.fmap_decode(fmap_blob)
+    for area in f['areas']:
+        label = area['name']
+        slot = label[-1]
+        if label[:-1] == 'VBLOCK_':
+            region_in = 'FW_MAIN_' + slot
+            region_out = label
+
+            input_data = os.path.join(self._tools.outdir, 'input.%s' % region_in)
+            output_data = os.path.join(self._tools.outdir, 'vblock.%s' % region_out)
+            self._tools.Run('cbfstool', [
+              cb_copy, 'read', '-r', region_in, '-f', input_data])
+
+            # Parse the file list to obtain the last entry. If its empty use
+            # its offset as the size of the CBFS to hash.
+            stdout = self._tools.Run('cbfstool',
+                [ cb_copy, 'print', '-k', '-r', region_in ])
+            # Fields are tab separated in the following order.
+            # Name    Offset  Type    Metadata Size   Data Size     Total Size
+            last_entry = stdout.strip().splitlines()[-1].split('\t')
+            if last_entry[0] == '(empty)' and last_entry[2] == 'null':
+                size = int(last_entry[1], 16)
+                self._tools.Run('truncate', [
+                    '--no-create', '--size', str(size), input_data])
+                self._out.Info('truncated FW_MAIN_%s to %d bytes' %
+                    (slot, size))
+
+            try:
+              prefix = self._keydir + '/'
+
+              self._tools.Run('vbutil_firmware', [
+                  '--vblock', output_data,
+                  '--keyblock', prefix + 'firmware.keyblock',
+                  '--signprivate', prefix + 'firmware_data_key.vbprivk',
+                  '--version', '1',
+                  '--fv', input_data,
+                  '--kernelkey', prefix + 'kernel_subkey.vbpubk',
+                  '--flags', '0',
+                ])
+
+            except CmdError as err:
+              raise PackError('Cannot make key block: vbutil_firmware failed\n%s' %
+                              err)
+            self._tools.Run('cbfstool', [cb_copy, 'write',
+                            '--fill-upward',
+                            '-f', output_data,
+                            '-r', label])
+
   def _CreateImage(self, gbb, fdt):
     """Create a full firmware image, along with various by-products.
 
@@ -866,6 +920,10 @@
     # Build the blobs out.
     self._BuildBlobs(pack, fdt)
 
+    # Now that blobs are built (and written into cb_with_fmap),
+    # create the vblocks
+    self._BuildKeyblocks(pack)
+
     self._out.Progress('Packing image')
     if gbb:
       pack.RequireAllEntries()