| # 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: |
| - content: List of phandles to entries to sign |
| - 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) |
| |
| Output files: |
| - input.<unique_name> - input file passed to futility |
| - vblock.<unique_name> - output file generated by futility (which is |
| used as the entry contents) |
| |
| 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 = b'' |
| 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 |
| |
| uniq = self.GetUniqueName() |
| output_fname = tools.GetOutputFilename('vblock.%s' % uniq) |
| input_fname = tools.GetOutputFilename('input.%s' % uniq) |
| 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) |
| self.SetContents(tools.ReadFile(output_fname)) |
| return True |