1# SPDX-License-Identifier: GPL-2.0+
2# Copyright 2022 Google LLC
3#
4"""Bintool implementation for futility
5
6futility (flash utility) is a tool for working with Chromium OS flash images.
7This implements just the features used by Binman.
8
9Documentation is at:
10   https://chromium.googlesource.com/chromiumos/platform/vboot/+/refs/heads/main/_vboot_reference/README
11
12Source code:
13   https://chromium.googlesource.com/chromiumos/platform/vboot/+/refs/heads/master/_vboot_reference/futility
14
15Here is the help:
16Usage: futility [options] COMMAND [args...]
17
18This is the unified firmware utility, which will eventually replace
19most of the distinct verified boot tools formerly produced by the
20vboot_reference package.
21
22When symlinked under the name of one of those previous tools, it should
23fully implement the original behavior. It can also be invoked directly
24as futility, followed by the original name as the first argument.
25
26Global options:
27
28  --vb1        Use only vboot v1.0 binary formats
29  --vb21       Use only vboot v2.1 binary formats
30  --debug      Be noisy about what's going on
31
32The following commands are built-in:
33
34  bdb                  Common boot flow utility
35  create               Create a keypair from an RSA .pem file
36  dump_fmap            Display FMAP contents from a firmware image
37  dump_kernel_config   Prints the kernel command line
38  gbb                  Manipulate the Google Binary Block (GBB)
39  gbb_utility          Legacy name for `gbb` command
40  help                 Show a bit of help (you're looking at it)
41  load_fmap            Replace the contents of specified FMAP areas
42  pcr                  Simulate a TPM PCR extension operation
43  show                 Display the content of various binary components
44  sign                 Sign / resign various binary components
45  update               Update system firmware
46  validate_rec_mrc     Validates content of Recovery MRC cache
47  vbutil_firmware      Verified boot firmware utility
48  vbutil_kernel        Creates, signs, and verifies the kernel partition
49  vbutil_key           Wraps RSA keys with vboot headers
50  vbutil_keyblock      Creates, signs, and verifies a keyblock
51  verify               Verify the signatures of various binary components
52  version              Show the futility source revision and build date
53"""
54
55from binman import bintool
56
57class Bintoolfutility(bintool.Bintool):
58    """Handles the 'futility' tool
59
60    futility (flash utility) is a tool for working with Chromium OS flash
61    images. This Bintool implements just the features used by Binman, related to
62    GBB creation and firmware signing.
63
64    A binary version of the tool can be fetched.
65
66    See `Chromium OS vboot documentation`_ for more information.
67
68    .. _`Chromium OS vboot documentation`:
69        https://chromium.googlesource.com/chromiumos/platform/vboot/+/refs/heads/main/_vboot_reference/README
70    """
71    def __init__(self, name):
72        super().__init__(name, 'Chromium OS firmware utility', r'^(.*)$', 'version')
73
74    def gbb_create(self, fname, sizes):
75        """Create a new Google Binary Block
76
77        Args:
78            fname (str): Filename to write to
79            sizes (list of int): Sizes of each regions:
80               hwid_size, rootkey_size, bmpfv_size, recoverykey_size
81
82        Returns:
83            str: Tool output
84        """
85        args = [
86            'gbb_utility',
87            '-c',
88            ','.join(['%#x' % size for size in sizes]),
89            fname
90            ]
91        return self.run_cmd(*args)
92
93    # pylint: disable=R0913
94    def gbb_set(self, fname, hwid, rootkey, recoverykey, flags, bmpfv):
95        """Set the parameters in a Google Binary Block
96
97        Args:
98            fname (str): Filename to update
99            hwid (str): Hardware ID to use
100            rootkey (str): Filename of root key, e.g. 'root_key.vbpubk'
101            recoverykey (str): Filename of recovery key,
102                e.g. 'recovery_key.vbpubk'
103            flags (int): GBB flags to use
104            bmpfv (str): Filename of firmware bitmaps (bmpblk file)
105
106        Returns:
107            str: Tool output
108        """
109        args = ['gbb_utility',
110            '-s',
111            f'--hwid={hwid}',
112            f'--rootkey={rootkey}',
113            f'--recoverykey={recoverykey}',
114            f'--flags={flags}',
115            f'--bmpfv={bmpfv}',
116            fname
117            ]
118        return self.run_cmd(*args)
119
120    def sign_firmware(self, vblock, keyblock, signprivate, version, firmware,
121                      kernelkey, flags):
122        """Sign firmware to create a vblock file
123
124        Args:
125            vblock (str): Filename to write the vblock too
126            keyblock (str): Filename of keyblock file
127            signprivate (str): Filename of private key
128            version (int): Version number
129            firmware (str): Filename of firmware binary to sign
130            kernelkey (str): Filename of kernel key
131            flags (int): Preamble flags
132
133        Returns:
134            str: Tool output
135        """
136        args = [
137            'vbutil_firmware',
138            '--vblock', vblock,
139            '--keyblock', keyblock,
140            '--signprivate', signprivate,
141            '--version', version,
142            '--fv', firmware,
143            '--kernelkey', kernelkey,
144            '--flags', flags
145            ]
146        return self.run_cmd(*args)
147
148    def fetch(self, method):
149        """Fetch handler for futility
150
151        This installs futility using a binary download.
152
153        Args:
154            method (FETCH_...): Method to use
155
156        Returns:
157            True if the file was fetched, None if a method other than FETCH_BIN
158            was requested
159
160        Raises:
161            Valuerror: Fetching could not be completed
162        """
163        if method != bintool.FETCH_BUILD:
164            return None
165
166        # The Chromium OS repo is here:
167        # https://chromium.googlesource.com/chromiumos/platform/vboot_reference/
168        #
169        # Unfortunately this requires logging in and obtaining a line for the
170        # .gitcookies file. So use a mirror instead.
171        result = self.build_from_git(
172            'https://github.com/sjg20/vboot_reference.git',
173            ['all'],
174            'build/futility/futility',
175            flags=['USE_FLASHROM=0'])
176        return result
177