1*8617a60dSAndroid Build Coastguard Worker /* Copyright 2021 The ChromiumOS Authors
2*8617a60dSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be
3*8617a60dSAndroid Build Coastguard Worker * found in the LICENSE file.
4*8617a60dSAndroid Build Coastguard Worker */
5*8617a60dSAndroid Build Coastguard Worker
6*8617a60dSAndroid Build Coastguard Worker #include <errno.h>
7*8617a60dSAndroid Build Coastguard Worker #include <fcntl.h>
8*8617a60dSAndroid Build Coastguard Worker #include <getopt.h>
9*8617a60dSAndroid Build Coastguard Worker #include <openssl/bn.h>
10*8617a60dSAndroid Build Coastguard Worker #include <openssl/pem.h>
11*8617a60dSAndroid Build Coastguard Worker #include <stdbool.h>
12*8617a60dSAndroid Build Coastguard Worker #include <stdlib.h>
13*8617a60dSAndroid Build Coastguard Worker #include <unistd.h>
14*8617a60dSAndroid Build Coastguard Worker
15*8617a60dSAndroid Build Coastguard Worker #include "fmap.h"
16*8617a60dSAndroid Build Coastguard Worker #include "futility.h"
17*8617a60dSAndroid Build Coastguard Worker #include "gsc_ro.h"
18*8617a60dSAndroid Build Coastguard Worker #include "host_key21.h"
19*8617a60dSAndroid Build Coastguard Worker #include "host_keyblock.h"
20*8617a60dSAndroid Build Coastguard Worker #include "host_misc.h"
21*8617a60dSAndroid Build Coastguard Worker #include "host_signature.h"
22*8617a60dSAndroid Build Coastguard Worker #include "host_p11.h"
23*8617a60dSAndroid Build Coastguard Worker
24*8617a60dSAndroid Build Coastguard Worker /*
25*8617a60dSAndroid Build Coastguard Worker * for testing purposes let's use
26*8617a60dSAndroid Build Coastguard Worker * - tests/devkeys/arv_root.vbprivk as the root private key
27*8617a60dSAndroid Build Coastguard Worker * - tests/devkeys/arv_root.vbpubk as the root public key
28*8617a60dSAndroid Build Coastguard Worker * used for signing of the platform public key
29*8617a60dSAndroid Build Coastguard Worker * - tests/devkeys/arv_platform.vbprivk signing platform key
30*8617a60dSAndroid Build Coastguard Worker * - tests/devkeys/arv_platform.vbpubk - public key used for signature
31*8617a60dSAndroid Build Coastguard Worker * verification
32*8617a60dSAndroid Build Coastguard Worker *------------
33*8617a60dSAndroid Build Coastguard Worker * Command to create the signed public key block in ~/tmp/packed:
34*8617a60dSAndroid Build Coastguard Worker *
35*8617a60dSAndroid Build Coastguard Worker ./build/futility/futility vbutil_keyblock --pack ~/tmp/packed \
36*8617a60dSAndroid Build Coastguard Worker --datapubkey tests/devkeys/arv_platform.vbpubk \
37*8617a60dSAndroid Build Coastguard Worker --signprivate tests/devkeys/arv_root.vbprivk
38*8617a60dSAndroid Build Coastguard Worker *------------
39*8617a60dSAndroid Build Coastguard Worker * Command to fill RO_GSCVD FMAP area in an AP firmware file. The input AP
40*8617a60dSAndroid Build Coastguard Worker * firmware file is ~/tmp/image-guybrush.serial.bin, the output signed
41*8617a60dSAndroid Build Coastguard Worker * AP firmware file is ~/tmp/guybrush-signed:
42*8617a60dSAndroid Build Coastguard Worker *
43*8617a60dSAndroid Build Coastguard Worker ./build/futility/futility gscvd --outfile ~/tmp/guybrush-signed \
44*8617a60dSAndroid Build Coastguard Worker -R 818100:10000,f00000:100,f80000:2000,f8c000:1000,0x00804000:0x00000800 \
45*8617a60dSAndroid Build Coastguard Worker -k ~/tmp/packed -p tests/devkeys/arv_platform.vbprivk -b 5a5a4352 \
46*8617a60dSAndroid Build Coastguard Worker -r tests/devkeys/arv_root.vbpubk ~/tmp/image-guybrush.serial.bin
47*8617a60dSAndroid Build Coastguard Worker *------------
48*8617a60dSAndroid Build Coastguard Worker * Command to validate a previously signed AP firmware file. The hash is the
49*8617a60dSAndroid Build Coastguard Worker * sha256sum of tests/devkeys/kernel_subkey.vbpubk:
50*8617a60dSAndroid Build Coastguard Worker *
51*8617a60dSAndroid Build Coastguard Worker build/futility/futility gscvd ~/tmp/guybrush-signed \
52*8617a60dSAndroid Build Coastguard Worker 3d74429f35be8d34bcb425d4397e2218e6961afed456a78ce30047f5b54ed158
53*8617a60dSAndroid Build Coastguard Worker */
54*8617a60dSAndroid Build Coastguard Worker
55*8617a60dSAndroid Build Coastguard Worker /* Command line options processing support. */
56*8617a60dSAndroid Build Coastguard Worker enum no_short_opts {
57*8617a60dSAndroid Build Coastguard Worker OPT_OUTFILE = 1000,
58*8617a60dSAndroid Build Coastguard Worker OPT_RO_GSCVD_FILE = 1001,
59*8617a60dSAndroid Build Coastguard Worker };
60*8617a60dSAndroid Build Coastguard Worker
61*8617a60dSAndroid Build Coastguard Worker static const struct option long_opts[] = {
62*8617a60dSAndroid Build Coastguard Worker /* name hasarg *flag val */
63*8617a60dSAndroid Build Coastguard Worker {"add_gbb", 0, NULL, 'G'},
64*8617a60dSAndroid Build Coastguard Worker {"board_id", 1, NULL, 'b'},
65*8617a60dSAndroid Build Coastguard Worker {"help", 0, NULL, 'h'},
66*8617a60dSAndroid Build Coastguard Worker {"keyblock", 1, NULL, 'k'},
67*8617a60dSAndroid Build Coastguard Worker {"outfile", 1, NULL, OPT_OUTFILE},
68*8617a60dSAndroid Build Coastguard Worker {"platform_priv", 1, NULL, 'p'},
69*8617a60dSAndroid Build Coastguard Worker {"ranges", 1, NULL, 'R'},
70*8617a60dSAndroid Build Coastguard Worker {"gscvd_out", 1, NULL, OPT_RO_GSCVD_FILE},
71*8617a60dSAndroid Build Coastguard Worker {"root_pub_key", 1, NULL, 'r'},
72*8617a60dSAndroid Build Coastguard Worker {}
73*8617a60dSAndroid Build Coastguard Worker };
74*8617a60dSAndroid Build Coastguard Worker
75*8617a60dSAndroid Build Coastguard Worker static const char *short_opts = "R:Gb:hk:p:r:";
76*8617a60dSAndroid Build Coastguard Worker
77*8617a60dSAndroid Build Coastguard Worker static const char usage[] =
78*8617a60dSAndroid Build Coastguard Worker "\n"
79*8617a60dSAndroid Build Coastguard Worker "This utility creates an RO verification space in the Chrome OS AP\n"
80*8617a60dSAndroid Build Coastguard Worker "firmware image, allows to validate a previously prepared image\n"
81*8617a60dSAndroid Build Coastguard Worker "containing the RO verification space, and prints out the hash of the\n"
82*8617a60dSAndroid Build Coastguard Worker "payload of the root public key.\n\n"
83*8617a60dSAndroid Build Coastguard Worker "Create a new GSCVD from scratch:\n"
84*8617a60dSAndroid Build Coastguard Worker " "MYNAME" gscvd -R <ranges> PARAMS <firmware image>\n\n"
85*8617a60dSAndroid Build Coastguard Worker "Re-sign an existing GSCVD with new keys, preserving ranges:\n"
86*8617a60dSAndroid Build Coastguard Worker " "MYNAME" gscvd PARAMS <firmware image>\n\n"
87*8617a60dSAndroid Build Coastguard Worker "Validate an existing GSCVD with given root key hash:\n"
88*8617a60dSAndroid Build Coastguard Worker " "MYNAME" gscvd <firmware image> [<root key hash in hex>]\n\n"
89*8617a60dSAndroid Build Coastguard Worker "Print the hash of a public root key:\n"
90*8617a60dSAndroid Build Coastguard Worker " "MYNAME" gscvd -r <root key .vpubk file>\n\n"
91*8617a60dSAndroid Build Coastguard Worker "Required PARAMS:\n"
92*8617a60dSAndroid Build Coastguard Worker " -b|--board_id <string|hex> The Board ID of the board for\n"
93*8617a60dSAndroid Build Coastguard Worker " which the image is signed.\n"
94*8617a60dSAndroid Build Coastguard Worker " Can be passed as a 4-letter\n"
95*8617a60dSAndroid Build Coastguard Worker " string or a hexadecimal number.\n"
96*8617a60dSAndroid Build Coastguard Worker " -r|--root_pub_key <file> The main public key, in .vbpubk\n"
97*8617a60dSAndroid Build Coastguard Worker " format, used to verify platform\n"
98*8617a60dSAndroid Build Coastguard Worker " key\n"
99*8617a60dSAndroid Build Coastguard Worker " -k|--keyblock <file> Signed platform public key in\n"
100*8617a60dSAndroid Build Coastguard Worker " .keyblock format, used for run\n"
101*8617a60dSAndroid Build Coastguard Worker " time RO verifcation\n"
102*8617a60dSAndroid Build Coastguard Worker " -p|--platform_priv <file> Private platform key in .vbprivk\n"
103*8617a60dSAndroid Build Coastguard Worker " format, used for signing RO\n"
104*8617a60dSAndroid Build Coastguard Worker " verification data\n"
105*8617a60dSAndroid Build Coastguard Worker "Optional PARAMS:\n"
106*8617a60dSAndroid Build Coastguard Worker " -G|--add_gbb Add the `GBB` FMAP section to the\n"
107*8617a60dSAndroid Build Coastguard Worker " ranges covered by the signature.\n"
108*8617a60dSAndroid Build Coastguard Worker " This option takes special care\n"
109*8617a60dSAndroid Build Coastguard Worker " to exclude the HWID (and its\n"
110*8617a60dSAndroid Build Coastguard Worker " digest) from this range.\n"
111*8617a60dSAndroid Build Coastguard Worker " -R|--ranges STRING Comma separated colon delimited\n"
112*8617a60dSAndroid Build Coastguard Worker " hex tuples <offset>:<size>, the\n"
113*8617a60dSAndroid Build Coastguard Worker " areas of the RO covered by the\n"
114*8617a60dSAndroid Build Coastguard Worker " signature, if omitted the\n"
115*8617a60dSAndroid Build Coastguard Worker " ranges are expected to be\n"
116*8617a60dSAndroid Build Coastguard Worker " present in the GSCVD section\n"
117*8617a60dSAndroid Build Coastguard Worker " of the input file\n"
118*8617a60dSAndroid Build Coastguard Worker " [--outfile] OUTFILE Output firmware image containing\n"
119*8617a60dSAndroid Build Coastguard Worker " RO verification information\n"
120*8617a60dSAndroid Build Coastguard Worker " [--gscvd_out] GSCVD_FILE A binary blob containing just the\n"
121*8617a60dSAndroid Build Coastguard Worker " unpadded RO_GSCVD section\n"
122*8617a60dSAndroid Build Coastguard Worker " -h|--help Print this message\n\n";
123*8617a60dSAndroid Build Coastguard Worker
124*8617a60dSAndroid Build Coastguard Worker /* Structure helping to keep track of the file mapped into memory. */
125*8617a60dSAndroid Build Coastguard Worker struct file_buf {
126*8617a60dSAndroid Build Coastguard Worker uint32_t len;
127*8617a60dSAndroid Build Coastguard Worker uint8_t *data;
128*8617a60dSAndroid Build Coastguard Worker int fd;
129*8617a60dSAndroid Build Coastguard Worker FmapAreaHeader *ro_gscvd;
130*8617a60dSAndroid Build Coastguard Worker /* Cached GBB information. */
131*8617a60dSAndroid Build Coastguard Worker const FmapAreaHeader *gbb_area;
132*8617a60dSAndroid Build Coastguard Worker uint32_t gbb_maxlen;
133*8617a60dSAndroid Build Coastguard Worker };
134*8617a60dSAndroid Build Coastguard Worker
135*8617a60dSAndroid Build Coastguard Worker /*
136*8617a60dSAndroid Build Coastguard Worker * Max number of RO ranges to cover. 32 is more than enough, this must be kept
137*8617a60dSAndroid Build Coastguard Worker * in sync with
138*8617a60dSAndroid Build Coastguard Worker * - AP_RO_MAX_NUM_RANGES in cr50/common/ap_ro_integrity_check.c
139*8617a60dSAndroid Build Coastguard Worker * - MAX_RO_RANGES in ti50/common/capsules/src/ap_ro_verification/gscvd.rs
140*8617a60dSAndroid Build Coastguard Worker */
141*8617a60dSAndroid Build Coastguard Worker #define MAX_RANGES 32
142*8617a60dSAndroid Build Coastguard Worker
143*8617a60dSAndroid Build Coastguard Worker /*
144*8617a60dSAndroid Build Coastguard Worker * Container keeping track of the set of ranges to include in hash
145*8617a60dSAndroid Build Coastguard Worker * calculation.
146*8617a60dSAndroid Build Coastguard Worker */
147*8617a60dSAndroid Build Coastguard Worker struct gscvd_ro_ranges {
148*8617a60dSAndroid Build Coastguard Worker size_t range_count;
149*8617a60dSAndroid Build Coastguard Worker struct gscvd_ro_range ranges[MAX_RANGES];
150*8617a60dSAndroid Build Coastguard Worker };
151*8617a60dSAndroid Build Coastguard Worker
152*8617a60dSAndroid Build Coastguard Worker /**
153*8617a60dSAndroid Build Coastguard Worker * Load the AP firmware file into memory.
154*8617a60dSAndroid Build Coastguard Worker *
155*8617a60dSAndroid Build Coastguard Worker * Map the requested file into memory, find RO_GSCVD area in the file, and
156*8617a60dSAndroid Build Coastguard Worker * cache the information in the passed in file_buf structure.
157*8617a60dSAndroid Build Coastguard Worker *
158*8617a60dSAndroid Build Coastguard Worker * @param file_name name of the AP firmware file
159*8617a60dSAndroid Build Coastguard Worker * @param file_buf pointer to the helper structure keeping information about
160*8617a60dSAndroid Build Coastguard Worker * the file
161*8617a60dSAndroid Build Coastguard Worker *
162*8617a60dSAndroid Build Coastguard Worker * @return 0 on success 1 on failure.
163*8617a60dSAndroid Build Coastguard Worker */
load_ap_firmware(const char * file_name,struct file_buf * file,int mode)164*8617a60dSAndroid Build Coastguard Worker static int load_ap_firmware(const char *file_name, struct file_buf *file,
165*8617a60dSAndroid Build Coastguard Worker int mode)
166*8617a60dSAndroid Build Coastguard Worker {
167*8617a60dSAndroid Build Coastguard Worker memset(file, 0, sizeof(*file));
168*8617a60dSAndroid Build Coastguard Worker
169*8617a60dSAndroid Build Coastguard Worker if (futil_open_and_map_file(file_name, &file->fd, mode, &file->data,
170*8617a60dSAndroid Build Coastguard Worker &file->len))
171*8617a60dSAndroid Build Coastguard Worker return 1;
172*8617a60dSAndroid Build Coastguard Worker
173*8617a60dSAndroid Build Coastguard Worker if (!fmap_find_by_name(file->data, file->len, NULL, "RO_GSCVD",
174*8617a60dSAndroid Build Coastguard Worker &file->ro_gscvd)) {
175*8617a60dSAndroid Build Coastguard Worker ERROR("Could not find RO_GSCVD in the FMAP\n");
176*8617a60dSAndroid Build Coastguard Worker futil_unmap_and_close_file(file->fd, mode, file->data,
177*8617a60dSAndroid Build Coastguard Worker file->len);
178*8617a60dSAndroid Build Coastguard Worker file->fd = -1;
179*8617a60dSAndroid Build Coastguard Worker file->data = NULL;
180*8617a60dSAndroid Build Coastguard Worker file->len = 0;
181*8617a60dSAndroid Build Coastguard Worker return 1;
182*8617a60dSAndroid Build Coastguard Worker }
183*8617a60dSAndroid Build Coastguard Worker
184*8617a60dSAndroid Build Coastguard Worker /*
185*8617a60dSAndroid Build Coastguard Worker * Try finding FMAP gbb area and validating the GBB. It's not a
186*8617a60dSAndroid Build Coastguard Worker * failure if GBB is not found, it might not be required after all.
187*8617a60dSAndroid Build Coastguard Worker */
188*8617a60dSAndroid Build Coastguard Worker FmapAreaHeader *area;
189*8617a60dSAndroid Build Coastguard Worker while (fmap_find_by_name(file->data, file->len, NULL, "GBB", &area)) {
190*8617a60dSAndroid Build Coastguard Worker struct vb2_gbb_header *gbb;
191*8617a60dSAndroid Build Coastguard Worker uint32_t maxlen;
192*8617a60dSAndroid Build Coastguard Worker
193*8617a60dSAndroid Build Coastguard Worker gbb = (void *)(file->data + area->area_offset);
194*8617a60dSAndroid Build Coastguard Worker
195*8617a60dSAndroid Build Coastguard Worker if (!futil_valid_gbb_header(gbb, area->area_size, &maxlen)) {
196*8617a60dSAndroid Build Coastguard Worker ERROR("GBB is invalid.\n");
197*8617a60dSAndroid Build Coastguard Worker break;
198*8617a60dSAndroid Build Coastguard Worker }
199*8617a60dSAndroid Build Coastguard Worker
200*8617a60dSAndroid Build Coastguard Worker /*
201*8617a60dSAndroid Build Coastguard Worker * This implementation relies on the fact that no meaningful
202*8617a60dSAndroid Build Coastguard Worker * fields come after the `hwid_digest` field in the header. If
203*8617a60dSAndroid Build Coastguard Worker * we ever make new GBB versions that add more fields, the
204*8617a60dSAndroid Build Coastguard Worker * code below and in add_gbb() needs to be adapted. Older
205*8617a60dSAndroid Build Coastguard Worker * versions than 1.2 or GBBs with a bmpblk are not expected
206*8617a60dSAndroid Build Coastguard Worker * with GSCVD images.
207*8617a60dSAndroid Build Coastguard Worker */
208*8617a60dSAndroid Build Coastguard Worker if (gbb->major_version != 1 || gbb->minor_version != 2 ||
209*8617a60dSAndroid Build Coastguard Worker gbb->bmpfv_size != 0) {
210*8617a60dSAndroid Build Coastguard Worker ERROR("Unsupported GBB version.\n");
211*8617a60dSAndroid Build Coastguard Worker break;
212*8617a60dSAndroid Build Coastguard Worker }
213*8617a60dSAndroid Build Coastguard Worker
214*8617a60dSAndroid Build Coastguard Worker
215*8617a60dSAndroid Build Coastguard Worker file->gbb_area = area;
216*8617a60dSAndroid Build Coastguard Worker file->gbb_maxlen = maxlen;
217*8617a60dSAndroid Build Coastguard Worker
218*8617a60dSAndroid Build Coastguard Worker break;
219*8617a60dSAndroid Build Coastguard Worker }
220*8617a60dSAndroid Build Coastguard Worker
221*8617a60dSAndroid Build Coastguard Worker return 0;
222*8617a60dSAndroid Build Coastguard Worker }
223*8617a60dSAndroid Build Coastguard Worker
224*8617a60dSAndroid Build Coastguard Worker /**
225*8617a60dSAndroid Build Coastguard Worker * Check if the passed in offset falls into the passed in FMAP area.
226*8617a60dSAndroid Build Coastguard Worker */
in_range(uint32_t offset,const FmapAreaHeader * ah)227*8617a60dSAndroid Build Coastguard Worker static bool in_range(uint32_t offset, const FmapAreaHeader *ah)
228*8617a60dSAndroid Build Coastguard Worker {
229*8617a60dSAndroid Build Coastguard Worker return (offset >= ah->area_offset) &&
230*8617a60dSAndroid Build Coastguard Worker (offset <= (ah->area_offset + ah->area_size));
231*8617a60dSAndroid Build Coastguard Worker }
232*8617a60dSAndroid Build Coastguard Worker
233*8617a60dSAndroid Build Coastguard Worker /**
234*8617a60dSAndroid Build Coastguard Worker * Check if the passed in range fits into the passed in FMAP area.
235*8617a60dSAndroid Build Coastguard Worker */
range_fits(const struct gscvd_ro_range * range,const FmapAreaHeader * ah)236*8617a60dSAndroid Build Coastguard Worker static bool range_fits(const struct gscvd_ro_range *range,
237*8617a60dSAndroid Build Coastguard Worker const FmapAreaHeader *ah)
238*8617a60dSAndroid Build Coastguard Worker {
239*8617a60dSAndroid Build Coastguard Worker if (in_range(range->offset, ah) &&
240*8617a60dSAndroid Build Coastguard Worker in_range(range->offset + range->size, ah))
241*8617a60dSAndroid Build Coastguard Worker return true;
242*8617a60dSAndroid Build Coastguard Worker
243*8617a60dSAndroid Build Coastguard Worker return false;
244*8617a60dSAndroid Build Coastguard Worker }
245*8617a60dSAndroid Build Coastguard Worker
246*8617a60dSAndroid Build Coastguard Worker /**
247*8617a60dSAndroid Build Coastguard Worker * Check if the passed in range overlaps with the area.
248*8617a60dSAndroid Build Coastguard Worker *
249*8617a60dSAndroid Build Coastguard Worker * @param range pointer to the range to check
250*8617a60dSAndroid Build Coastguard Worker * @param offset offset of the area to check against
251*8617a60dSAndroid Build Coastguard Worker * @param size size of the area to check against
252*8617a60dSAndroid Build Coastguard Worker *
253*8617a60dSAndroid Build Coastguard Worker * @return true if range overlaps with the area, false otherwise.
254*8617a60dSAndroid Build Coastguard Worker */
range_overlaps(const struct gscvd_ro_range * range,uint32_t offset,size_t size)255*8617a60dSAndroid Build Coastguard Worker static bool range_overlaps(const struct gscvd_ro_range *range, uint32_t offset,
256*8617a60dSAndroid Build Coastguard Worker size_t size)
257*8617a60dSAndroid Build Coastguard Worker {
258*8617a60dSAndroid Build Coastguard Worker if (((range->offset + range->size) <= offset) ||
259*8617a60dSAndroid Build Coastguard Worker (offset + size) <= range->offset)
260*8617a60dSAndroid Build Coastguard Worker return false;
261*8617a60dSAndroid Build Coastguard Worker
262*8617a60dSAndroid Build Coastguard Worker ERROR("Range %x..+%x overlaps with %x..+%zx\n", range->offset,
263*8617a60dSAndroid Build Coastguard Worker range->size, offset, size);
264*8617a60dSAndroid Build Coastguard Worker
265*8617a60dSAndroid Build Coastguard Worker return true;
266*8617a60dSAndroid Build Coastguard Worker }
267*8617a60dSAndroid Build Coastguard Worker
268*8617a60dSAndroid Build Coastguard Worker /*
269*8617a60dSAndroid Build Coastguard Worker * Check validity of the passed in ranges.
270*8617a60dSAndroid Build Coastguard Worker *
271*8617a60dSAndroid Build Coastguard Worker * All ranges must
272*8617a60dSAndroid Build Coastguard Worker * - fit into the WP_RO FMAP area
273*8617a60dSAndroid Build Coastguard Worker * - not overlap with the RO_GSCVD FMAP area
274*8617a60dSAndroid Build Coastguard Worker * - not overlap with each other
275*8617a60dSAndroid Build Coastguard Worker *
276*8617a60dSAndroid Build Coastguard Worker * @param ranges - pointer to the container of ranges to check
277*8617a60dSAndroid Build Coastguard Worker * @param file - pointer to the file layout descriptor
278*8617a60dSAndroid Build Coastguard Worker *
279*8617a60dSAndroid Build Coastguard Worker * @return zero on success, -1 on failures
280*8617a60dSAndroid Build Coastguard Worker */
verify_ranges(const struct gscvd_ro_ranges * ranges,const struct file_buf * file)281*8617a60dSAndroid Build Coastguard Worker static int verify_ranges(const struct gscvd_ro_ranges *ranges,
282*8617a60dSAndroid Build Coastguard Worker const struct file_buf *file)
283*8617a60dSAndroid Build Coastguard Worker {
284*8617a60dSAndroid Build Coastguard Worker size_t i;
285*8617a60dSAndroid Build Coastguard Worker FmapAreaHeader *wp_ro;
286*8617a60dSAndroid Build Coastguard Worker FmapAreaHeader *si_all;
287*8617a60dSAndroid Build Coastguard Worker int errorcount;
288*8617a60dSAndroid Build Coastguard Worker
289*8617a60dSAndroid Build Coastguard Worker if (!fmap_find_by_name(file->data, file->len, NULL, "WP_RO", &wp_ro)) {
290*8617a60dSAndroid Build Coastguard Worker ERROR("Could not find WP_RO in the FMAP\n");
291*8617a60dSAndroid Build Coastguard Worker return 1;
292*8617a60dSAndroid Build Coastguard Worker }
293*8617a60dSAndroid Build Coastguard Worker
294*8617a60dSAndroid Build Coastguard Worker /* Intel boards can have an SI_ALL region that's not in WP_RO but is
295*8617a60dSAndroid Build Coastguard Worker protected by platform-specific mechanisms, and may still contain
296*8617a60dSAndroid Build Coastguard Worker components that we want to protect from physical attack. */
297*8617a60dSAndroid Build Coastguard Worker if (!fmap_find_by_name(file->data, file->len, NULL, "SI_ALL", &si_all))
298*8617a60dSAndroid Build Coastguard Worker si_all = NULL;
299*8617a60dSAndroid Build Coastguard Worker
300*8617a60dSAndroid Build Coastguard Worker errorcount = 0;
301*8617a60dSAndroid Build Coastguard Worker for (i = 0; i < ranges->range_count; i++) {
302*8617a60dSAndroid Build Coastguard Worker size_t j;
303*8617a60dSAndroid Build Coastguard Worker
304*8617a60dSAndroid Build Coastguard Worker /* Must fit into WP_RO or SI_ALL. */
305*8617a60dSAndroid Build Coastguard Worker if (!range_fits(ranges->ranges + i, wp_ro) &&
306*8617a60dSAndroid Build Coastguard Worker (!si_all || !range_fits(ranges->ranges + i, si_all))) {
307*8617a60dSAndroid Build Coastguard Worker ERROR("Range %#x..+%#x does not fit in WP_RO/SI_ALL\n",
308*8617a60dSAndroid Build Coastguard Worker ranges->ranges[i].offset,
309*8617a60dSAndroid Build Coastguard Worker ranges->ranges[i].size);
310*8617a60dSAndroid Build Coastguard Worker errorcount++;
311*8617a60dSAndroid Build Coastguard Worker }
312*8617a60dSAndroid Build Coastguard Worker
313*8617a60dSAndroid Build Coastguard Worker /* Must not overlap with RO_GSCVD. */
314*8617a60dSAndroid Build Coastguard Worker if (range_overlaps(ranges->ranges + i,
315*8617a60dSAndroid Build Coastguard Worker file->ro_gscvd->area_offset,
316*8617a60dSAndroid Build Coastguard Worker file->ro_gscvd->area_size))
317*8617a60dSAndroid Build Coastguard Worker errorcount++;
318*8617a60dSAndroid Build Coastguard Worker
319*8617a60dSAndroid Build Coastguard Worker /* The last range is nothing to compare against. */
320*8617a60dSAndroid Build Coastguard Worker if (i == ranges->range_count - 1)
321*8617a60dSAndroid Build Coastguard Worker break;
322*8617a60dSAndroid Build Coastguard Worker
323*8617a60dSAndroid Build Coastguard Worker /* Must not overlap with all following ranges. */
324*8617a60dSAndroid Build Coastguard Worker for (j = i + 1; j < ranges->range_count; j++)
325*8617a60dSAndroid Build Coastguard Worker if (range_overlaps(ranges->ranges + i,
326*8617a60dSAndroid Build Coastguard Worker ranges->ranges[j].offset,
327*8617a60dSAndroid Build Coastguard Worker ranges->ranges[j].size))
328*8617a60dSAndroid Build Coastguard Worker errorcount++;
329*8617a60dSAndroid Build Coastguard Worker }
330*8617a60dSAndroid Build Coastguard Worker
331*8617a60dSAndroid Build Coastguard Worker return errorcount ? -1 : 0;
332*8617a60dSAndroid Build Coastguard Worker }
333*8617a60dSAndroid Build Coastguard Worker
334*8617a60dSAndroid Build Coastguard Worker /**
335*8617a60dSAndroid Build Coastguard Worker * Parse range specification supplied by the user.
336*8617a60dSAndroid Build Coastguard Worker *
337*8617a60dSAndroid Build Coastguard Worker * The input is a string of the following format:
338*8617a60dSAndroid Build Coastguard Worker * <hex base>:<hex size>[,<hex base>:<hex size>[,...]]
339*8617a60dSAndroid Build Coastguard Worker *
340*8617a60dSAndroid Build Coastguard Worker * @param input user input, part of the command line
341*8617a60dSAndroid Build Coastguard Worker * @param output pointer to the ranges container
342*8617a60dSAndroid Build Coastguard Worker *
343*8617a60dSAndroid Build Coastguard Worker * @return zero on success, -1 on failure
344*8617a60dSAndroid Build Coastguard Worker */
parse_ranges(const char * input,struct gscvd_ro_ranges * output)345*8617a60dSAndroid Build Coastguard Worker static int parse_ranges(const char *input, struct gscvd_ro_ranges *output)
346*8617a60dSAndroid Build Coastguard Worker {
347*8617a60dSAndroid Build Coastguard Worker char *cursor;
348*8617a60dSAndroid Build Coastguard Worker char *delim;
349*8617a60dSAndroid Build Coastguard Worker char *str = strdup(input);
350*8617a60dSAndroid Build Coastguard Worker int rv = 0;
351*8617a60dSAndroid Build Coastguard Worker
352*8617a60dSAndroid Build Coastguard Worker if (!str) {
353*8617a60dSAndroid Build Coastguard Worker ERROR("Failed to allocate memory for ranges string copy!\n");
354*8617a60dSAndroid Build Coastguard Worker return -1;
355*8617a60dSAndroid Build Coastguard Worker }
356*8617a60dSAndroid Build Coastguard Worker
357*8617a60dSAndroid Build Coastguard Worker cursor = str;
358*8617a60dSAndroid Build Coastguard Worker do {
359*8617a60dSAndroid Build Coastguard Worker char *colon;
360*8617a60dSAndroid Build Coastguard Worker char *e;
361*8617a60dSAndroid Build Coastguard Worker
362*8617a60dSAndroid Build Coastguard Worker if (output->range_count >= ARRAY_SIZE(output->ranges)) {
363*8617a60dSAndroid Build Coastguard Worker ERROR("Too many ranges!\n");
364*8617a60dSAndroid Build Coastguard Worker rv = -1;
365*8617a60dSAndroid Build Coastguard Worker break;
366*8617a60dSAndroid Build Coastguard Worker }
367*8617a60dSAndroid Build Coastguard Worker
368*8617a60dSAndroid Build Coastguard Worker delim = strchr(cursor, ',');
369*8617a60dSAndroid Build Coastguard Worker if (delim)
370*8617a60dSAndroid Build Coastguard Worker *delim = '\0';
371*8617a60dSAndroid Build Coastguard Worker colon = strchr(cursor, ':');
372*8617a60dSAndroid Build Coastguard Worker if (!colon) {
373*8617a60dSAndroid Build Coastguard Worker rv = -1;
374*8617a60dSAndroid Build Coastguard Worker break;
375*8617a60dSAndroid Build Coastguard Worker }
376*8617a60dSAndroid Build Coastguard Worker *colon = '\0';
377*8617a60dSAndroid Build Coastguard Worker
378*8617a60dSAndroid Build Coastguard Worker errno = 0;
379*8617a60dSAndroid Build Coastguard Worker output->ranges[output->range_count].offset =
380*8617a60dSAndroid Build Coastguard Worker strtol(cursor, &e, 16);
381*8617a60dSAndroid Build Coastguard Worker if (errno || *e) {
382*8617a60dSAndroid Build Coastguard Worker rv = -1;
383*8617a60dSAndroid Build Coastguard Worker break;
384*8617a60dSAndroid Build Coastguard Worker }
385*8617a60dSAndroid Build Coastguard Worker
386*8617a60dSAndroid Build Coastguard Worker output->ranges[output->range_count].size =
387*8617a60dSAndroid Build Coastguard Worker strtol(colon + 1, &e, 16);
388*8617a60dSAndroid Build Coastguard Worker if (errno || *e) {
389*8617a60dSAndroid Build Coastguard Worker rv = -1;
390*8617a60dSAndroid Build Coastguard Worker break;
391*8617a60dSAndroid Build Coastguard Worker }
392*8617a60dSAndroid Build Coastguard Worker
393*8617a60dSAndroid Build Coastguard Worker output->range_count++;
394*8617a60dSAndroid Build Coastguard Worker cursor = delim + 1;
395*8617a60dSAndroid Build Coastguard Worker /* Iterate until there is no more commas. */
396*8617a60dSAndroid Build Coastguard Worker } while (delim);
397*8617a60dSAndroid Build Coastguard Worker
398*8617a60dSAndroid Build Coastguard Worker free(str);
399*8617a60dSAndroid Build Coastguard Worker if (rv)
400*8617a60dSAndroid Build Coastguard Worker ERROR("Misformatted ranges string\n");
401*8617a60dSAndroid Build Coastguard Worker
402*8617a60dSAndroid Build Coastguard Worker return rv;
403*8617a60dSAndroid Build Coastguard Worker }
404*8617a60dSAndroid Build Coastguard Worker
405*8617a60dSAndroid Build Coastguard Worker /**
406*8617a60dSAndroid Build Coastguard Worker * Add GBB to ranges.
407*8617a60dSAndroid Build Coastguard Worker *
408*8617a60dSAndroid Build Coastguard Worker * Splits the `GBB` FMAP section into separate ranges to exclude the HWID string
409*8617a60dSAndroid Build Coastguard Worker * and the `hwid_digest` field in the header. Will also exclude the empty area
410*8617a60dSAndroid Build Coastguard Worker * behind the end of the actual GBB data.
411*8617a60dSAndroid Build Coastguard Worker *
412*8617a60dSAndroid Build Coastguard Worker * @param ranges pointer to the ranges container
413*8617a60dSAndroid Build Coastguard Worker * @param file pointer to the AP firmware file layout descriptor
414*8617a60dSAndroid Build Coastguard Worker */
add_gbb(struct gscvd_ro_ranges * ranges,const struct file_buf * file)415*8617a60dSAndroid Build Coastguard Worker static int add_gbb(struct gscvd_ro_ranges *ranges, const struct file_buf *file)
416*8617a60dSAndroid Build Coastguard Worker {
417*8617a60dSAndroid Build Coastguard Worker if (!file->gbb_area) {
418*8617a60dSAndroid Build Coastguard Worker ERROR("Could not find a GBB area in the FMAP.\n");
419*8617a60dSAndroid Build Coastguard Worker return 1;
420*8617a60dSAndroid Build Coastguard Worker }
421*8617a60dSAndroid Build Coastguard Worker
422*8617a60dSAndroid Build Coastguard Worker const struct vb2_gbb_header *gbb = (void *)(file->data +
423*8617a60dSAndroid Build Coastguard Worker file->gbb_area->area_offset);
424*8617a60dSAndroid Build Coastguard Worker uint32_t lower_key_offset = VB2_MIN(gbb->rootkey_offset,
425*8617a60dSAndroid Build Coastguard Worker gbb->recovery_key_offset);
426*8617a60dSAndroid Build Coastguard Worker if (gbb->hwid_offset > lower_key_offset) {
427*8617a60dSAndroid Build Coastguard Worker ERROR("Weird GBB layout (HWID should come first)\n");
428*8617a60dSAndroid Build Coastguard Worker return 1;
429*8617a60dSAndroid Build Coastguard Worker }
430*8617a60dSAndroid Build Coastguard Worker
431*8617a60dSAndroid Build Coastguard Worker if (ranges->range_count >= ARRAY_SIZE(ranges->ranges) - 2) {
432*8617a60dSAndroid Build Coastguard Worker ERROR("Too many ranges, can't fit GBB!\n");
433*8617a60dSAndroid Build Coastguard Worker return 1;
434*8617a60dSAndroid Build Coastguard Worker }
435*8617a60dSAndroid Build Coastguard Worker
436*8617a60dSAndroid Build Coastguard Worker ranges->ranges[ranges->range_count].offset =
437*8617a60dSAndroid Build Coastguard Worker file->gbb_area->area_offset;
438*8617a60dSAndroid Build Coastguard Worker ranges->ranges[ranges->range_count].size =
439*8617a60dSAndroid Build Coastguard Worker offsetof(struct vb2_gbb_header, hwid_digest);
440*8617a60dSAndroid Build Coastguard Worker ranges->range_count++;
441*8617a60dSAndroid Build Coastguard Worker
442*8617a60dSAndroid Build Coastguard Worker ranges->ranges[ranges->range_count].offset =
443*8617a60dSAndroid Build Coastguard Worker file->gbb_area->area_offset + lower_key_offset;
444*8617a60dSAndroid Build Coastguard Worker ranges->ranges[ranges->range_count].size =
445*8617a60dSAndroid Build Coastguard Worker file->gbb_maxlen - lower_key_offset;
446*8617a60dSAndroid Build Coastguard Worker ranges->range_count++;
447*8617a60dSAndroid Build Coastguard Worker
448*8617a60dSAndroid Build Coastguard Worker return 0;
449*8617a60dSAndroid Build Coastguard Worker }
450*8617a60dSAndroid Build Coastguard Worker
451*8617a60dSAndroid Build Coastguard Worker /**
452*8617a60dSAndroid Build Coastguard Worker * Extend AP RO hash digest with data from an address range.
453*8617a60dSAndroid Build Coastguard Worker *
454*8617a60dSAndroid Build Coastguard Worker * If the flags_offset value is non zero and happens to fall into the passed
455*8617a60dSAndroid Build Coastguard Worker * in range, do not read values from flash in the flags_offset..+flags_size
456*8617a60dSAndroid Build Coastguard Worker * range, instead feed zeros to the hashing function.
457*8617a60dSAndroid Build Coastguard Worker *
458*8617a60dSAndroid Build Coastguard Worker * NOTE that flags are expected to fully fit into the range, cases of overlap
459*8617a60dSAndroid Build Coastguard Worker * are not supported.
460*8617a60dSAndroid Build Coastguard Worker *
461*8617a60dSAndroid Build Coastguard Worker * @param ap_firmware_file pointer to the AP firmware file layout descriptor
462*8617a60dSAndroid Build Coastguard Worker * @param dc pointer to the hash calculating context
463*8617a60dSAndroid Build Coastguard Worker * @param offset offset of the beginning of the range in AP SPI flash
464*8617a60dSAndroid Build Coastguard Worker * @param size size of the range
465*8617a60dSAndroid Build Coastguard Worker * @param flags_offset if nonzero - offset of the GBB flags field in
466*8617a60dSAndroid Build Coastguard Worker * AP SPI flash
467*8617a60dSAndroid Build Coastguard Worker *
468*8617a60dSAndroid Build Coastguard Worker * @return VB2_SUCCESS or digest extension error, if any.
469*8617a60dSAndroid Build Coastguard Worker */
extend_digest(const struct file_buf * ap_firmware_file,struct vb2_digest_context * dc,uint32_t offset,uint32_t size,uint32_t flags_offset)470*8617a60dSAndroid Build Coastguard Worker static vb2_error_t extend_digest(const struct file_buf *ap_firmware_file,
471*8617a60dSAndroid Build Coastguard Worker struct vb2_digest_context *dc,
472*8617a60dSAndroid Build Coastguard Worker uint32_t offset,
473*8617a60dSAndroid Build Coastguard Worker uint32_t size,
474*8617a60dSAndroid Build Coastguard Worker uint32_t flags_offset)
475*8617a60dSAndroid Build Coastguard Worker {
476*8617a60dSAndroid Build Coastguard Worker /* Define it as array to simplify calling vb2_digest_extend() below. */
477*8617a60dSAndroid Build Coastguard Worker const uint8_t flags[sizeof(vb2_gbb_flags_t)] = {0};
478*8617a60dSAndroid Build Coastguard Worker
479*8617a60dSAndroid Build Coastguard Worker VB2_DEBUG("%s: %#x..+%#x\n", __func__, offset, size);
480*8617a60dSAndroid Build Coastguard Worker
481*8617a60dSAndroid Build Coastguard Worker if (flags_offset &&
482*8617a60dSAndroid Build Coastguard Worker (flags_offset >= offset) &&
483*8617a60dSAndroid Build Coastguard Worker (flags_offset < (offset + size))) {
484*8617a60dSAndroid Build Coastguard Worker uint32_t flags_size;
485*8617a60dSAndroid Build Coastguard Worker vb2_error_t rv;
486*8617a60dSAndroid Build Coastguard Worker
487*8617a60dSAndroid Build Coastguard Worker /*
488*8617a60dSAndroid Build Coastguard Worker * This range includes GBB flags, which need to be zeroized.
489*8617a60dSAndroid Build Coastguard Worker *
490*8617a60dSAndroid Build Coastguard Worker * First get the hash of up to the flags.
491*8617a60dSAndroid Build Coastguard Worker */
492*8617a60dSAndroid Build Coastguard Worker rv = vb2_digest_extend(dc, ap_firmware_file->data + offset,
493*8617a60dSAndroid Build Coastguard Worker flags_offset - offset);
494*8617a60dSAndroid Build Coastguard Worker if (rv != VB2_SUCCESS)
495*8617a60dSAndroid Build Coastguard Worker return rv;
496*8617a60dSAndroid Build Coastguard Worker
497*8617a60dSAndroid Build Coastguard Worker size -= flags_offset - offset;
498*8617a60dSAndroid Build Coastguard Worker offset = flags_offset;
499*8617a60dSAndroid Build Coastguard Worker
500*8617a60dSAndroid Build Coastguard Worker /* Now hash the flag space, maybe partially. */
501*8617a60dSAndroid Build Coastguard Worker flags_size = VB2_MIN(size, sizeof(flags));
502*8617a60dSAndroid Build Coastguard Worker rv = vb2_digest_extend(dc, flags, flags_size);
503*8617a60dSAndroid Build Coastguard Worker if (rv != VB2_SUCCESS)
504*8617a60dSAndroid Build Coastguard Worker return rv;
505*8617a60dSAndroid Build Coastguard Worker
506*8617a60dSAndroid Build Coastguard Worker /* Update size and offset to cover the rest of the range. */
507*8617a60dSAndroid Build Coastguard Worker size -= flags_size;
508*8617a60dSAndroid Build Coastguard Worker
509*8617a60dSAndroid Build Coastguard Worker offset += flags_size;
510*8617a60dSAndroid Build Coastguard Worker }
511*8617a60dSAndroid Build Coastguard Worker
512*8617a60dSAndroid Build Coastguard Worker return vb2_digest_extend(dc,ap_firmware_file->data + offset, size);
513*8617a60dSAndroid Build Coastguard Worker }
514*8617a60dSAndroid Build Coastguard Worker
515*8617a60dSAndroid Build Coastguard Worker /**
516*8617a60dSAndroid Build Coastguard Worker * Calculate hash of the RO ranges.
517*8617a60dSAndroid Build Coastguard Worker *
518*8617a60dSAndroid Build Coastguard Worker * @param ap_firmware_file pointer to the AP firmware file layout descriptor
519*8617a60dSAndroid Build Coastguard Worker * @param ranges pointer to the container of ranges to include in hash
520*8617a60dSAndroid Build Coastguard Worker * calculation
521*8617a60dSAndroid Build Coastguard Worker * @param hash_alg algorithm to use for hashing
522*8617a60dSAndroid Build Coastguard Worker * @param digest memory to copy the calculated hash to
523*8617a60dSAndroid Build Coastguard Worker * @param digest_ size requested size of the digest, padded with zeros if the
524*8617a60dSAndroid Build Coastguard Worker * SHA digest size is smaller than digest_size
525*8617a60dSAndroid Build Coastguard Worker * @param override_gbb_flags if true, replace GBB flags value with zero
526*8617a60dSAndroid Build Coastguard Worker *
527*8617a60dSAndroid Build Coastguard Worker * @return zero on success, -1 on failure.
528*8617a60dSAndroid Build Coastguard Worker */
calculate_ranges_digest(const struct file_buf * ap_firmware_file,const struct gscvd_ro_ranges * ranges,enum vb2_hash_algorithm hash_alg,void * digest,size_t digest_size,bool override_gbb_flags)529*8617a60dSAndroid Build Coastguard Worker static int calculate_ranges_digest(const struct file_buf *ap_firmware_file,
530*8617a60dSAndroid Build Coastguard Worker const struct gscvd_ro_ranges *ranges,
531*8617a60dSAndroid Build Coastguard Worker enum vb2_hash_algorithm hash_alg,
532*8617a60dSAndroid Build Coastguard Worker void *digest, size_t digest_size,
533*8617a60dSAndroid Build Coastguard Worker bool override_gbb_flags)
534*8617a60dSAndroid Build Coastguard Worker {
535*8617a60dSAndroid Build Coastguard Worker struct vb2_digest_context dc;
536*8617a60dSAndroid Build Coastguard Worker size_t i;
537*8617a60dSAndroid Build Coastguard Worker uint32_t flags_offset = 0;
538*8617a60dSAndroid Build Coastguard Worker
539*8617a60dSAndroid Build Coastguard Worker if (override_gbb_flags && ap_firmware_file->gbb_area)
540*8617a60dSAndroid Build Coastguard Worker flags_offset = offsetof(struct vb2_gbb_header, flags) +
541*8617a60dSAndroid Build Coastguard Worker ap_firmware_file->gbb_area->area_offset;
542*8617a60dSAndroid Build Coastguard Worker
543*8617a60dSAndroid Build Coastguard Worker /* Calculate the ranges digest. */
544*8617a60dSAndroid Build Coastguard Worker if (vb2_digest_init(&dc, false, hash_alg, 0) != VB2_SUCCESS) {
545*8617a60dSAndroid Build Coastguard Worker ERROR("Failed to init digest!\n");
546*8617a60dSAndroid Build Coastguard Worker return 1;
547*8617a60dSAndroid Build Coastguard Worker }
548*8617a60dSAndroid Build Coastguard Worker
549*8617a60dSAndroid Build Coastguard Worker for (i = 0; i < ranges->range_count; i++) {
550*8617a60dSAndroid Build Coastguard Worker if (extend_digest(ap_firmware_file, &dc,
551*8617a60dSAndroid Build Coastguard Worker ranges->ranges[i].offset,
552*8617a60dSAndroid Build Coastguard Worker ranges->ranges[i].size,
553*8617a60dSAndroid Build Coastguard Worker flags_offset) != VB2_SUCCESS) {
554*8617a60dSAndroid Build Coastguard Worker ERROR("Failed to extend digest!\n");
555*8617a60dSAndroid Build Coastguard Worker return -1;
556*8617a60dSAndroid Build Coastguard Worker }
557*8617a60dSAndroid Build Coastguard Worker }
558*8617a60dSAndroid Build Coastguard Worker
559*8617a60dSAndroid Build Coastguard Worker memset(digest, 0, digest_size);
560*8617a60dSAndroid Build Coastguard Worker if (vb2_digest_finalize(&dc, digest, digest_size) != VB2_SUCCESS) {
561*8617a60dSAndroid Build Coastguard Worker ERROR("Failed to finalize digest!\n");
562*8617a60dSAndroid Build Coastguard Worker return -1;
563*8617a60dSAndroid Build Coastguard Worker }
564*8617a60dSAndroid Build Coastguard Worker
565*8617a60dSAndroid Build Coastguard Worker return 0;
566*8617a60dSAndroid Build Coastguard Worker }
567*8617a60dSAndroid Build Coastguard Worker
568*8617a60dSAndroid Build Coastguard Worker /**
569*8617a60dSAndroid Build Coastguard Worker * Build GSC verification data.
570*8617a60dSAndroid Build Coastguard Worker *
571*8617a60dSAndroid Build Coastguard Worker * Calculate size of the structure including the signature and the root key,
572*8617a60dSAndroid Build Coastguard Worker * allocate memory, fill up the structure, calculate AP RO ranges digest and
573*8617a60dSAndroid Build Coastguard Worker * then the GVD signature.
574*8617a60dSAndroid Build Coastguard Worker *
575*8617a60dSAndroid Build Coastguard Worker * @param ap_firmware_file pointer to the AP firmware file layout descriptor
576*8617a60dSAndroid Build Coastguard Worker * @param ranges pointer to the container of ranges to include in verification
577*8617a60dSAndroid Build Coastguard Worker * @param root_pubk pointer to the root pubk container
578*8617a60dSAndroid Build Coastguard Worker * @param privk pointer to the private key to use for signing
579*8617a60dSAndroid Build Coastguard Worker * @param board_id Board ID value to use.
580*8617a60dSAndroid Build Coastguard Worker *
581*8617a60dSAndroid Build Coastguard Worker * @return pointer to the created GVD (to be freed by the caller) on success,
582*8617a60dSAndroid Build Coastguard Worker * NULL on failure.
583*8617a60dSAndroid Build Coastguard Worker */
584*8617a60dSAndroid Build Coastguard Worker static
create_gvd(struct file_buf * ap_firmware_file,struct gscvd_ro_ranges * ranges,const struct vb2_packed_key * root_pubk,const struct vb2_private_key * privk,uint32_t board_id)585*8617a60dSAndroid Build Coastguard Worker struct gsc_verification_data *create_gvd(struct file_buf *ap_firmware_file,
586*8617a60dSAndroid Build Coastguard Worker struct gscvd_ro_ranges *ranges,
587*8617a60dSAndroid Build Coastguard Worker const struct vb2_packed_key *root_pubk,
588*8617a60dSAndroid Build Coastguard Worker const struct vb2_private_key *privk,
589*8617a60dSAndroid Build Coastguard Worker uint32_t board_id)
590*8617a60dSAndroid Build Coastguard Worker {
591*8617a60dSAndroid Build Coastguard Worker struct gsc_verification_data *gvd;
592*8617a60dSAndroid Build Coastguard Worker size_t total_size;
593*8617a60dSAndroid Build Coastguard Worker size_t sig_size;
594*8617a60dSAndroid Build Coastguard Worker size_t ranges_size;
595*8617a60dSAndroid Build Coastguard Worker struct vb2_signature *sig;
596*8617a60dSAndroid Build Coastguard Worker const FmapHeader *fmh;
597*8617a60dSAndroid Build Coastguard Worker
598*8617a60dSAndroid Build Coastguard Worker sig_size = vb2_rsa_sig_size(privk->sig_alg);
599*8617a60dSAndroid Build Coastguard Worker ranges_size = ranges->range_count * sizeof(struct gscvd_ro_range);
600*8617a60dSAndroid Build Coastguard Worker total_size = sizeof(struct gsc_verification_data) +
601*8617a60dSAndroid Build Coastguard Worker root_pubk->key_size + sig_size + ranges_size;
602*8617a60dSAndroid Build Coastguard Worker
603*8617a60dSAndroid Build Coastguard Worker gvd = calloc(total_size, 1);
604*8617a60dSAndroid Build Coastguard Worker
605*8617a60dSAndroid Build Coastguard Worker if (!gvd) {
606*8617a60dSAndroid Build Coastguard Worker ERROR("Failed to allocate %zd bytes for gvd\n", total_size);
607*8617a60dSAndroid Build Coastguard Worker return NULL;
608*8617a60dSAndroid Build Coastguard Worker }
609*8617a60dSAndroid Build Coastguard Worker
610*8617a60dSAndroid Build Coastguard Worker gvd->gv_magic = GSC_VD_MAGIC;
611*8617a60dSAndroid Build Coastguard Worker gvd->size = total_size;
612*8617a60dSAndroid Build Coastguard Worker gvd->gsc_board_id = board_id;
613*8617a60dSAndroid Build Coastguard Worker gvd->rollback_counter = GSC_VD_ROLLBACK_COUNTER;
614*8617a60dSAndroid Build Coastguard Worker
615*8617a60dSAndroid Build Coastguard Worker /* Guaranteed to succeed. */
616*8617a60dSAndroid Build Coastguard Worker fmh = fmap_find(ap_firmware_file->data, ap_firmware_file->len);
617*8617a60dSAndroid Build Coastguard Worker
618*8617a60dSAndroid Build Coastguard Worker gvd->fmap_location = (uintptr_t)fmh - (uintptr_t)ap_firmware_file->data;
619*8617a60dSAndroid Build Coastguard Worker
620*8617a60dSAndroid Build Coastguard Worker gvd->hash_alg = VB2_HASH_SHA256;
621*8617a60dSAndroid Build Coastguard Worker
622*8617a60dSAndroid Build Coastguard Worker if (calculate_ranges_digest(ap_firmware_file, ranges, gvd->hash_alg,
623*8617a60dSAndroid Build Coastguard Worker gvd->ranges_digest,
624*8617a60dSAndroid Build Coastguard Worker sizeof(gvd->ranges_digest),
625*8617a60dSAndroid Build Coastguard Worker true)) {
626*8617a60dSAndroid Build Coastguard Worker free(gvd);
627*8617a60dSAndroid Build Coastguard Worker return NULL;
628*8617a60dSAndroid Build Coastguard Worker }
629*8617a60dSAndroid Build Coastguard Worker
630*8617a60dSAndroid Build Coastguard Worker /* Prepare signature header. */
631*8617a60dSAndroid Build Coastguard Worker vb2_init_signature(&gvd->sig_header,
632*8617a60dSAndroid Build Coastguard Worker (uint8_t *)(gvd + 1) + ranges_size,
633*8617a60dSAndroid Build Coastguard Worker sig_size,
634*8617a60dSAndroid Build Coastguard Worker sizeof(struct gsc_verification_data) + ranges_size);
635*8617a60dSAndroid Build Coastguard Worker
636*8617a60dSAndroid Build Coastguard Worker /* Copy root key into the structure. */
637*8617a60dSAndroid Build Coastguard Worker vb2_init_packed_key(&gvd->root_key_header,
638*8617a60dSAndroid Build Coastguard Worker (uint8_t *)(gvd + 1) + ranges_size + sig_size,
639*8617a60dSAndroid Build Coastguard Worker root_pubk->key_size);
640*8617a60dSAndroid Build Coastguard Worker vb2_copy_packed_key(&gvd->root_key_header, root_pubk);
641*8617a60dSAndroid Build Coastguard Worker
642*8617a60dSAndroid Build Coastguard Worker /* Copy ranges into the ranges section. */
643*8617a60dSAndroid Build Coastguard Worker gvd->range_count = ranges->range_count;
644*8617a60dSAndroid Build Coastguard Worker memcpy(gvd->ranges, ranges->ranges, ranges_size);
645*8617a60dSAndroid Build Coastguard Worker
646*8617a60dSAndroid Build Coastguard Worker sig = vb2_calculate_signature((uint8_t *)gvd,
647*8617a60dSAndroid Build Coastguard Worker sizeof(struct gsc_verification_data) +
648*8617a60dSAndroid Build Coastguard Worker ranges_size, privk);
649*8617a60dSAndroid Build Coastguard Worker if (!sig) {
650*8617a60dSAndroid Build Coastguard Worker ERROR("Failed to calculate signature\n");
651*8617a60dSAndroid Build Coastguard Worker free(gvd);
652*8617a60dSAndroid Build Coastguard Worker return NULL;
653*8617a60dSAndroid Build Coastguard Worker }
654*8617a60dSAndroid Build Coastguard Worker
655*8617a60dSAndroid Build Coastguard Worker /* Copy signature body into GVD after some basic checks. */
656*8617a60dSAndroid Build Coastguard Worker if ((sig_size == sig->sig_size) &&
657*8617a60dSAndroid Build Coastguard Worker (gvd->sig_header.data_size == sig->data_size)) {
658*8617a60dSAndroid Build Coastguard Worker vb2_copy_signature(&gvd->sig_header, sig);
659*8617a60dSAndroid Build Coastguard Worker } else {
660*8617a60dSAndroid Build Coastguard Worker ERROR("Inconsistent signature headers\n");
661*8617a60dSAndroid Build Coastguard Worker free(sig);
662*8617a60dSAndroid Build Coastguard Worker free(gvd);
663*8617a60dSAndroid Build Coastguard Worker return NULL;
664*8617a60dSAndroid Build Coastguard Worker }
665*8617a60dSAndroid Build Coastguard Worker
666*8617a60dSAndroid Build Coastguard Worker free(sig);
667*8617a60dSAndroid Build Coastguard Worker
668*8617a60dSAndroid Build Coastguard Worker return gvd;
669*8617a60dSAndroid Build Coastguard Worker }
670*8617a60dSAndroid Build Coastguard Worker
671*8617a60dSAndroid Build Coastguard Worker /**
672*8617a60dSAndroid Build Coastguard Worker * Fill RO_GSCVD FMAP area.
673*8617a60dSAndroid Build Coastguard Worker *
674*8617a60dSAndroid Build Coastguard Worker * All trust chain components have been verified, AP RO sections digest
675*8617a60dSAndroid Build Coastguard Worker * calculated, and GVD signature created; put it all together in the dedicated
676*8617a60dSAndroid Build Coastguard Worker * FMAP area and save in a binary blob if requested.
677*8617a60dSAndroid Build Coastguard Worker *
678*8617a60dSAndroid Build Coastguard Worker * @param ap_firmware_file pointer to the AP firmware file layout descriptor
679*8617a60dSAndroid Build Coastguard Worker * @param gvd pointer to the GVD header
680*8617a60dSAndroid Build Coastguard Worker * @param keyblock pointer to the keyblock container
681*8617a60dSAndroid Build Coastguard Worker * @param gscvd_file_name if not NULL the name of the file to save the
682*8617a60dSAndroid Build Coastguard Worker * RO_GSCVD section in.
683*8617a60dSAndroid Build Coastguard Worker * @return zero on success, -1 on failure
684*8617a60dSAndroid Build Coastguard Worker */
fill_gvd_area(struct file_buf * ap_firmware_file,struct gsc_verification_data * gvd,struct vb2_keyblock * keyblock,const char * gscvd_file_name)685*8617a60dSAndroid Build Coastguard Worker static int fill_gvd_area(struct file_buf *ap_firmware_file,
686*8617a60dSAndroid Build Coastguard Worker struct gsc_verification_data *gvd,
687*8617a60dSAndroid Build Coastguard Worker struct vb2_keyblock *keyblock,
688*8617a60dSAndroid Build Coastguard Worker const char *gscvd_file_name)
689*8617a60dSAndroid Build Coastguard Worker {
690*8617a60dSAndroid Build Coastguard Worker size_t total;
691*8617a60dSAndroid Build Coastguard Worker uint8_t *cursor;
692*8617a60dSAndroid Build Coastguard Worker
693*8617a60dSAndroid Build Coastguard Worker /* How much room is needed for the whole thing? */
694*8617a60dSAndroid Build Coastguard Worker total = gvd->size + keyblock->keyblock_size;
695*8617a60dSAndroid Build Coastguard Worker
696*8617a60dSAndroid Build Coastguard Worker if (total > ap_firmware_file->ro_gscvd->area_size) {
697*8617a60dSAndroid Build Coastguard Worker ERROR("GVD section does not fit, %zd > %d\n",
698*8617a60dSAndroid Build Coastguard Worker total, ap_firmware_file->ro_gscvd->area_size);
699*8617a60dSAndroid Build Coastguard Worker return -1;
700*8617a60dSAndroid Build Coastguard Worker }
701*8617a60dSAndroid Build Coastguard Worker
702*8617a60dSAndroid Build Coastguard Worker cursor = ap_firmware_file->data +
703*8617a60dSAndroid Build Coastguard Worker ap_firmware_file->ro_gscvd->area_offset;
704*8617a60dSAndroid Build Coastguard Worker
705*8617a60dSAndroid Build Coastguard Worker /* Copy GSC verification data */
706*8617a60dSAndroid Build Coastguard Worker memcpy(cursor, gvd, gvd->size);
707*8617a60dSAndroid Build Coastguard Worker cursor += gvd->size;
708*8617a60dSAndroid Build Coastguard Worker
709*8617a60dSAndroid Build Coastguard Worker /* Keyblock, size includes everything. */
710*8617a60dSAndroid Build Coastguard Worker memcpy(cursor, keyblock, keyblock->keyblock_size);
711*8617a60dSAndroid Build Coastguard Worker
712*8617a60dSAndroid Build Coastguard Worker if (gscvd_file_name) {
713*8617a60dSAndroid Build Coastguard Worker if (vb2_write_file(gscvd_file_name, cursor - gvd->size,
714*8617a60dSAndroid Build Coastguard Worker total) != VB2_SUCCESS)
715*8617a60dSAndroid Build Coastguard Worker return -1;
716*8617a60dSAndroid Build Coastguard Worker }
717*8617a60dSAndroid Build Coastguard Worker return 0;
718*8617a60dSAndroid Build Coastguard Worker }
719*8617a60dSAndroid Build Coastguard Worker
720*8617a60dSAndroid Build Coastguard Worker /**
721*8617a60dSAndroid Build Coastguard Worker * Initialize a work buffer structure.
722*8617a60dSAndroid Build Coastguard Worker *
723*8617a60dSAndroid Build Coastguard Worker * Embedded vboot reference code does not use malloc/free, it uses the so
724*8617a60dSAndroid Build Coastguard Worker * called work buffer structure to provide a poor man's memory management
725*8617a60dSAndroid Build Coastguard Worker * tool. This program uses some of the embedded library functions, let's
726*8617a60dSAndroid Build Coastguard Worker * implement work buffer support to keep the embedded code happy.
727*8617a60dSAndroid Build Coastguard Worker *
728*8617a60dSAndroid Build Coastguard Worker * @param wb pointer to the workubffer structure to initialize
729*8617a60dSAndroid Build Coastguard Worker * @param size size of the buffer to allocate
730*8617a60dSAndroid Build Coastguard Worker *
731*8617a60dSAndroid Build Coastguard Worker * @return pointer to the allocated buffer on success, NULL on failure.
732*8617a60dSAndroid Build Coastguard Worker */
init_wb(struct vb2_workbuf * wb,size_t size)733*8617a60dSAndroid Build Coastguard Worker static void *init_wb(struct vb2_workbuf *wb, size_t size)
734*8617a60dSAndroid Build Coastguard Worker {
735*8617a60dSAndroid Build Coastguard Worker void *buf = malloc(size);
736*8617a60dSAndroid Build Coastguard Worker
737*8617a60dSAndroid Build Coastguard Worker if (!buf)
738*8617a60dSAndroid Build Coastguard Worker ERROR("Failed to allocate workblock of %zd\n", size);
739*8617a60dSAndroid Build Coastguard Worker else
740*8617a60dSAndroid Build Coastguard Worker vb2_workbuf_init(wb, buf, size);
741*8617a60dSAndroid Build Coastguard Worker
742*8617a60dSAndroid Build Coastguard Worker return buf;
743*8617a60dSAndroid Build Coastguard Worker }
744*8617a60dSAndroid Build Coastguard Worker
745*8617a60dSAndroid Build Coastguard Worker /**
746*8617a60dSAndroid Build Coastguard Worker * Validate that platform key keyblock was signed by the root key.
747*8617a60dSAndroid Build Coastguard Worker *
748*8617a60dSAndroid Build Coastguard Worker * This function performs the same step the GSC is supposed to perform:
749*8617a60dSAndroid Build Coastguard Worker * validate the platform key keyblock signature using the root public key.
750*8617a60dSAndroid Build Coastguard Worker *
751*8617a60dSAndroid Build Coastguard Worker * @param root_pubk pointer to the root public key container
752*8617a60dSAndroid Build Coastguard Worker * @param kblock pointer to the platform public key keyblock
753*8617a60dSAndroid Build Coastguard Worker *
754*8617a60dSAndroid Build Coastguard Worker * @return 0 on success, -1 on failure
755*8617a60dSAndroid Build Coastguard Worker */
validate_pubk_signature(const struct vb2_packed_key * root_pubk,struct vb2_keyblock * kblock)756*8617a60dSAndroid Build Coastguard Worker static int validate_pubk_signature(const struct vb2_packed_key *root_pubk,
757*8617a60dSAndroid Build Coastguard Worker struct vb2_keyblock *kblock)
758*8617a60dSAndroid Build Coastguard Worker {
759*8617a60dSAndroid Build Coastguard Worker struct vb2_public_key pubk;
760*8617a60dSAndroid Build Coastguard Worker struct vb2_workbuf wb;
761*8617a60dSAndroid Build Coastguard Worker uint32_t kbsize;
762*8617a60dSAndroid Build Coastguard Worker int rv;
763*8617a60dSAndroid Build Coastguard Worker void *buf;
764*8617a60dSAndroid Build Coastguard Worker
765*8617a60dSAndroid Build Coastguard Worker if (vb2_unpack_key(&pubk, root_pubk) != VB2_SUCCESS) {
766*8617a60dSAndroid Build Coastguard Worker ERROR("Failed to unpack public key\n");
767*8617a60dSAndroid Build Coastguard Worker return -1;
768*8617a60dSAndroid Build Coastguard Worker }
769*8617a60dSAndroid Build Coastguard Worker
770*8617a60dSAndroid Build Coastguard Worker /* Let's create an ample sized work buffer. */
771*8617a60dSAndroid Build Coastguard Worker buf = init_wb(&wb, 8192);
772*8617a60dSAndroid Build Coastguard Worker if (!buf)
773*8617a60dSAndroid Build Coastguard Worker return -1;
774*8617a60dSAndroid Build Coastguard Worker
775*8617a60dSAndroid Build Coastguard Worker rv = -1;
776*8617a60dSAndroid Build Coastguard Worker do {
777*8617a60dSAndroid Build Coastguard Worker void *work;
778*8617a60dSAndroid Build Coastguard Worker
779*8617a60dSAndroid Build Coastguard Worker kbsize = kblock->keyblock_size;
780*8617a60dSAndroid Build Coastguard Worker work = vb2_workbuf_alloc(&wb, kbsize);
781*8617a60dSAndroid Build Coastguard Worker if (!work) {
782*8617a60dSAndroid Build Coastguard Worker ERROR("Failed to allocate workblock space %d\n",
783*8617a60dSAndroid Build Coastguard Worker kbsize);
784*8617a60dSAndroid Build Coastguard Worker break;
785*8617a60dSAndroid Build Coastguard Worker }
786*8617a60dSAndroid Build Coastguard Worker
787*8617a60dSAndroid Build Coastguard Worker memcpy(work, kblock, kbsize);
788*8617a60dSAndroid Build Coastguard Worker
789*8617a60dSAndroid Build Coastguard Worker if (vb2_verify_keyblock(work, kbsize, &pubk, &wb) !=
790*8617a60dSAndroid Build Coastguard Worker VB2_SUCCESS) {
791*8617a60dSAndroid Build Coastguard Worker ERROR("Root and keyblock mismatch\n");
792*8617a60dSAndroid Build Coastguard Worker break;
793*8617a60dSAndroid Build Coastguard Worker }
794*8617a60dSAndroid Build Coastguard Worker
795*8617a60dSAndroid Build Coastguard Worker rv = 0;
796*8617a60dSAndroid Build Coastguard Worker } while (false);
797*8617a60dSAndroid Build Coastguard Worker
798*8617a60dSAndroid Build Coastguard Worker free(buf);
799*8617a60dSAndroid Build Coastguard Worker
800*8617a60dSAndroid Build Coastguard Worker return rv;
801*8617a60dSAndroid Build Coastguard Worker }
802*8617a60dSAndroid Build Coastguard Worker
803*8617a60dSAndroid Build Coastguard Worker /**
804*8617a60dSAndroid Build Coastguard Worker * Validate that private and public parts of the platform key match.
805*8617a60dSAndroid Build Coastguard Worker *
806*8617a60dSAndroid Build Coastguard Worker * This is a fairly routine validation, the N components of the private and
807*8617a60dSAndroid Build Coastguard Worker * public RSA keys are compared.
808*8617a60dSAndroid Build Coastguard Worker *
809*8617a60dSAndroid Build Coastguard Worker * @param keyblock pointer to the keyblock containing the public key
810*8617a60dSAndroid Build Coastguard Worker * @param plat_privk pointer to the matching private key
811*8617a60dSAndroid Build Coastguard Worker *
812*8617a60dSAndroid Build Coastguard Worker * @return 0 on success, nonzero on failure
813*8617a60dSAndroid Build Coastguard Worker */
validate_privk(struct vb2_keyblock * kblock,struct vb2_private_key * plat_privk)814*8617a60dSAndroid Build Coastguard Worker static int validate_privk(struct vb2_keyblock *kblock,
815*8617a60dSAndroid Build Coastguard Worker struct vb2_private_key *plat_privk)
816*8617a60dSAndroid Build Coastguard Worker {
817*8617a60dSAndroid Build Coastguard Worker BIGNUM *privn;
818*8617a60dSAndroid Build Coastguard Worker BIGNUM *pubn;
819*8617a60dSAndroid Build Coastguard Worker struct vb2_public_key pubk;
820*8617a60dSAndroid Build Coastguard Worker int rv = -1; // Speculatively set to error return value.
821*8617a60dSAndroid Build Coastguard Worker
822*8617a60dSAndroid Build Coastguard Worker privn = pubn = NULL;
823*8617a60dSAndroid Build Coastguard Worker
824*8617a60dSAndroid Build Coastguard Worker if (plat_privk->key_location != PRIVATE_KEY_P11) {
825*8617a60dSAndroid Build Coastguard Worker RSA_get0_key(plat_privk->rsa_private_key, (const BIGNUM **)&privn,
826*8617a60dSAndroid Build Coastguard Worker NULL, NULL);
827*8617a60dSAndroid Build Coastguard Worker } else {
828*8617a60dSAndroid Build Coastguard Worker uint32_t size;
829*8617a60dSAndroid Build Coastguard Worker uint8_t *bytes;
830*8617a60dSAndroid Build Coastguard Worker
831*8617a60dSAndroid Build Coastguard Worker bytes = pkcs11_get_modulus(plat_privk->p11_key, &size);
832*8617a60dSAndroid Build Coastguard Worker if (bytes == NULL) {
833*8617a60dSAndroid Build Coastguard Worker ERROR("Failed to retrieve private key modulus\n");
834*8617a60dSAndroid Build Coastguard Worker return rv;
835*8617a60dSAndroid Build Coastguard Worker }
836*8617a60dSAndroid Build Coastguard Worker
837*8617a60dSAndroid Build Coastguard Worker privn = BN_bin2bn(bytes, size, NULL);
838*8617a60dSAndroid Build Coastguard Worker free(bytes);
839*8617a60dSAndroid Build Coastguard Worker
840*8617a60dSAndroid Build Coastguard Worker if (!privn) {
841*8617a60dSAndroid Build Coastguard Worker ERROR("Failed to allocate BN for priv key modulus\n");
842*8617a60dSAndroid Build Coastguard Worker return rv;
843*8617a60dSAndroid Build Coastguard Worker }
844*8617a60dSAndroid Build Coastguard Worker }
845*8617a60dSAndroid Build Coastguard Worker
846*8617a60dSAndroid Build Coastguard Worker if (vb2_unpack_key(&pubk, &kblock->data_key) != VB2_SUCCESS) {
847*8617a60dSAndroid Build Coastguard Worker ERROR("Failed to unpack public key\n");
848*8617a60dSAndroid Build Coastguard Worker return rv;
849*8617a60dSAndroid Build Coastguard Worker }
850*8617a60dSAndroid Build Coastguard Worker
851*8617a60dSAndroid Build Coastguard Worker pubn = BN_lebin2bn((uint8_t *)pubk.n, vb2_rsa_sig_size(pubk.sig_alg),
852*8617a60dSAndroid Build Coastguard Worker NULL);
853*8617a60dSAndroid Build Coastguard Worker if (pubn) {
854*8617a60dSAndroid Build Coastguard Worker rv = BN_cmp(pubn, privn);
855*8617a60dSAndroid Build Coastguard Worker BN_free(pubn);
856*8617a60dSAndroid Build Coastguard Worker if (rv)
857*8617a60dSAndroid Build Coastguard Worker ERROR("Public/private key N mismatch!\n");
858*8617a60dSAndroid Build Coastguard Worker } else {
859*8617a60dSAndroid Build Coastguard Worker ERROR("Failed to allocate BN for pub key modulus\n");
860*8617a60dSAndroid Build Coastguard Worker }
861*8617a60dSAndroid Build Coastguard Worker
862*8617a60dSAndroid Build Coastguard Worker if (plat_privk->key_location == PRIVATE_KEY_P11)
863*8617a60dSAndroid Build Coastguard Worker BN_free(privn);
864*8617a60dSAndroid Build Coastguard Worker
865*8617a60dSAndroid Build Coastguard Worker return rv;
866*8617a60dSAndroid Build Coastguard Worker }
867*8617a60dSAndroid Build Coastguard Worker
868*8617a60dSAndroid Build Coastguard Worker /**
869*8617a60dSAndroid Build Coastguard Worker * Copy ranges from AP firmware file into gscvd_ro_ranges container
870*8617a60dSAndroid Build Coastguard Worker *
871*8617a60dSAndroid Build Coastguard Worker * While copying the ranges verify that they do not overlap.
872*8617a60dSAndroid Build Coastguard Worker *
873*8617a60dSAndroid Build Coastguard Worker * @param ap_firmware_file pointer to the AP firmware file layout descriptor
874*8617a60dSAndroid Build Coastguard Worker * @param gvd pointer to the GVD header followed by the ranges
875*8617a60dSAndroid Build Coastguard Worker * @param ranges pointer to the ranges container to copy ranges to
876*8617a60dSAndroid Build Coastguard Worker *
877*8617a60dSAndroid Build Coastguard Worker * @return 0 on successful copy nonzero on errors.
878*8617a60dSAndroid Build Coastguard Worker */
copy_ranges(const struct file_buf * ap_firmware_file,const struct gsc_verification_data * gvd,struct gscvd_ro_ranges * ranges)879*8617a60dSAndroid Build Coastguard Worker static int copy_ranges(const struct file_buf *ap_firmware_file,
880*8617a60dSAndroid Build Coastguard Worker const struct gsc_verification_data *gvd,
881*8617a60dSAndroid Build Coastguard Worker struct gscvd_ro_ranges *ranges)
882*8617a60dSAndroid Build Coastguard Worker {
883*8617a60dSAndroid Build Coastguard Worker ranges->range_count = gvd->range_count;
884*8617a60dSAndroid Build Coastguard Worker memcpy(ranges->ranges, gvd->ranges,
885*8617a60dSAndroid Build Coastguard Worker sizeof(ranges->ranges[0]) * ranges->range_count);
886*8617a60dSAndroid Build Coastguard Worker
887*8617a60dSAndroid Build Coastguard Worker return verify_ranges(ranges, ap_firmware_file);
888*8617a60dSAndroid Build Coastguard Worker }
889*8617a60dSAndroid Build Coastguard Worker
890*8617a60dSAndroid Build Coastguard Worker /**
891*8617a60dSAndroid Build Coastguard Worker * Basic validation of GVD included in a AP firmware file.
892*8617a60dSAndroid Build Coastguard Worker *
893*8617a60dSAndroid Build Coastguard Worker * This is not a cryptographic verification, just a check that the structure
894*8617a60dSAndroid Build Coastguard Worker * makes sense and the expected values are found in certain fields.
895*8617a60dSAndroid Build Coastguard Worker *
896*8617a60dSAndroid Build Coastguard Worker * @param gvd pointer to the GVD header followed by the ranges
897*8617a60dSAndroid Build Coastguard Worker * @param ap_firmware_file pointer to the AP firmware file layout descriptor
898*8617a60dSAndroid Build Coastguard Worker *
899*8617a60dSAndroid Build Coastguard Worker * @return zero on success, -1 on failure.
900*8617a60dSAndroid Build Coastguard Worker */
validate_gvd(const struct gsc_verification_data * gvd,const struct file_buf * ap_firmware_file)901*8617a60dSAndroid Build Coastguard Worker static int validate_gvd(const struct gsc_verification_data *gvd,
902*8617a60dSAndroid Build Coastguard Worker const struct file_buf *ap_firmware_file)
903*8617a60dSAndroid Build Coastguard Worker {
904*8617a60dSAndroid Build Coastguard Worker const FmapHeader *fmh;
905*8617a60dSAndroid Build Coastguard Worker
906*8617a60dSAndroid Build Coastguard Worker if (gvd->gv_magic != GSC_VD_MAGIC) {
907*8617a60dSAndroid Build Coastguard Worker ERROR("Incorrect gscvd magic %x\n", gvd->gv_magic);
908*8617a60dSAndroid Build Coastguard Worker return -1;
909*8617a60dSAndroid Build Coastguard Worker }
910*8617a60dSAndroid Build Coastguard Worker
911*8617a60dSAndroid Build Coastguard Worker if (!gvd->range_count || (gvd->range_count > MAX_RANGES)) {
912*8617a60dSAndroid Build Coastguard Worker ERROR("Incorrect gscvd range count %d\n", gvd->range_count);
913*8617a60dSAndroid Build Coastguard Worker return -1;
914*8617a60dSAndroid Build Coastguard Worker }
915*8617a60dSAndroid Build Coastguard Worker
916*8617a60dSAndroid Build Coastguard Worker /* Guaranteed to succeed. */
917*8617a60dSAndroid Build Coastguard Worker fmh = fmap_find(ap_firmware_file->data, ap_firmware_file->len);
918*8617a60dSAndroid Build Coastguard Worker
919*8617a60dSAndroid Build Coastguard Worker if (gvd->fmap_location !=
920*8617a60dSAndroid Build Coastguard Worker ((uintptr_t)fmh - (uintptr_t)ap_firmware_file->data)) {
921*8617a60dSAndroid Build Coastguard Worker ERROR("Incorrect gscvd fmap offset %x\n", gvd->fmap_location);
922*8617a60dSAndroid Build Coastguard Worker return -1;
923*8617a60dSAndroid Build Coastguard Worker }
924*8617a60dSAndroid Build Coastguard Worker
925*8617a60dSAndroid Build Coastguard Worker /* Make sure signature and root key fit. */
926*8617a60dSAndroid Build Coastguard Worker if (vb2_verify_signature_inside(gvd, gvd->size, &gvd->sig_header) !=
927*8617a60dSAndroid Build Coastguard Worker VB2_SUCCESS) {
928*8617a60dSAndroid Build Coastguard Worker ERROR("Corrupted signature header in GVD\n");
929*8617a60dSAndroid Build Coastguard Worker return -1;
930*8617a60dSAndroid Build Coastguard Worker }
931*8617a60dSAndroid Build Coastguard Worker
932*8617a60dSAndroid Build Coastguard Worker if (vb2_verify_packed_key_inside(gvd, gvd->size,
933*8617a60dSAndroid Build Coastguard Worker &gvd->root_key_header) !=
934*8617a60dSAndroid Build Coastguard Worker VB2_SUCCESS) {
935*8617a60dSAndroid Build Coastguard Worker ERROR("Corrupted root key header in GVD\n");
936*8617a60dSAndroid Build Coastguard Worker return -1;
937*8617a60dSAndroid Build Coastguard Worker }
938*8617a60dSAndroid Build Coastguard Worker
939*8617a60dSAndroid Build Coastguard Worker return 0;
940*8617a60dSAndroid Build Coastguard Worker }
941*8617a60dSAndroid Build Coastguard Worker
942*8617a60dSAndroid Build Coastguard Worker /**
943*8617a60dSAndroid Build Coastguard Worker * Validate GVD signature.
944*8617a60dSAndroid Build Coastguard Worker *
945*8617a60dSAndroid Build Coastguard Worker * Given the entire GVD space (header plus ranges array), the signature and
946*8617a60dSAndroid Build Coastguard Worker * the public key, verify that the signature matches.
947*8617a60dSAndroid Build Coastguard Worker *
948*8617a60dSAndroid Build Coastguard Worker * @param gvd pointer to gsc_verification_data followed by the ranges array
949*8617a60dSAndroid Build Coastguard Worker * @param gvd_signature pointer to the vb2 signature container
950*8617a60dSAndroid Build Coastguard Worker * @param packedk pointer to the keyblock containing the public key
951*8617a60dSAndroid Build Coastguard Worker *
952*8617a60dSAndroid Build Coastguard Worker * @return zero on success, non-zero on failure
953*8617a60dSAndroid Build Coastguard Worker */
validate_gvd_signature(struct gsc_verification_data * gvd,const struct vb2_packed_key * packedk)954*8617a60dSAndroid Build Coastguard Worker static int validate_gvd_signature(struct gsc_verification_data *gvd,
955*8617a60dSAndroid Build Coastguard Worker const struct vb2_packed_key *packedk)
956*8617a60dSAndroid Build Coastguard Worker {
957*8617a60dSAndroid Build Coastguard Worker struct vb2_workbuf wb;
958*8617a60dSAndroid Build Coastguard Worker void *buf;
959*8617a60dSAndroid Build Coastguard Worker int rv;
960*8617a60dSAndroid Build Coastguard Worker struct vb2_public_key pubk;
961*8617a60dSAndroid Build Coastguard Worker size_t signed_size;
962*8617a60dSAndroid Build Coastguard Worker
963*8617a60dSAndroid Build Coastguard Worker /* Extract public key from the public key keyblock. */
964*8617a60dSAndroid Build Coastguard Worker if (vb2_unpack_key(&pubk, packedk) != VB2_SUCCESS) {
965*8617a60dSAndroid Build Coastguard Worker ERROR("Failed to unpack public key\n");
966*8617a60dSAndroid Build Coastguard Worker return -1;
967*8617a60dSAndroid Build Coastguard Worker }
968*8617a60dSAndroid Build Coastguard Worker
969*8617a60dSAndroid Build Coastguard Worker /* Let's create an ample sized work buffer. */
970*8617a60dSAndroid Build Coastguard Worker buf = init_wb(&wb, 8192);
971*8617a60dSAndroid Build Coastguard Worker if (!buf)
972*8617a60dSAndroid Build Coastguard Worker return -1;
973*8617a60dSAndroid Build Coastguard Worker
974*8617a60dSAndroid Build Coastguard Worker signed_size = sizeof(struct gsc_verification_data) +
975*8617a60dSAndroid Build Coastguard Worker gvd->range_count * sizeof(gvd->ranges[0]);
976*8617a60dSAndroid Build Coastguard Worker
977*8617a60dSAndroid Build Coastguard Worker rv = vb2_verify_data((const uint8_t *)gvd, signed_size,
978*8617a60dSAndroid Build Coastguard Worker &gvd->sig_header,
979*8617a60dSAndroid Build Coastguard Worker &pubk, &wb);
980*8617a60dSAndroid Build Coastguard Worker
981*8617a60dSAndroid Build Coastguard Worker free(buf);
982*8617a60dSAndroid Build Coastguard Worker return rv;
983*8617a60dSAndroid Build Coastguard Worker }
984*8617a60dSAndroid Build Coastguard Worker
985*8617a60dSAndroid Build Coastguard Worker /*
986*8617a60dSAndroid Build Coastguard Worker * Try retrieving GVD ranges from the passed in AP firmware file.
987*8617a60dSAndroid Build Coastguard Worker *
988*8617a60dSAndroid Build Coastguard Worker * The passed in ranges structure is set to the set of ranges retrieved from
989*8617a60dSAndroid Build Coastguard Worker * the firmware file, if any.
990*8617a60dSAndroid Build Coastguard Worker */
try_retrieving_ranges_from_the_image(const char * file_name,struct gscvd_ro_ranges * ranges,struct file_buf * ap_firmware_file)991*8617a60dSAndroid Build Coastguard Worker static void try_retrieving_ranges_from_the_image(const char *file_name,
992*8617a60dSAndroid Build Coastguard Worker struct gscvd_ro_ranges *ranges,
993*8617a60dSAndroid Build Coastguard Worker struct file_buf
994*8617a60dSAndroid Build Coastguard Worker *ap_firmware_file)
995*8617a60dSAndroid Build Coastguard Worker {
996*8617a60dSAndroid Build Coastguard Worker struct gsc_verification_data *gvd;
997*8617a60dSAndroid Build Coastguard Worker size_t i;
998*8617a60dSAndroid Build Coastguard Worker
999*8617a60dSAndroid Build Coastguard Worker ranges->range_count = 0;
1000*8617a60dSAndroid Build Coastguard Worker
1001*8617a60dSAndroid Build Coastguard Worker /* Look for ranges in GVD and copy them if found. */
1002*8617a60dSAndroid Build Coastguard Worker gvd = (struct gsc_verification_data
1003*8617a60dSAndroid Build Coastguard Worker *)(ap_firmware_file->data +
1004*8617a60dSAndroid Build Coastguard Worker ap_firmware_file->ro_gscvd->area_offset);
1005*8617a60dSAndroid Build Coastguard Worker
1006*8617a60dSAndroid Build Coastguard Worker if (validate_gvd(gvd, ap_firmware_file))
1007*8617a60dSAndroid Build Coastguard Worker return;
1008*8617a60dSAndroid Build Coastguard Worker
1009*8617a60dSAndroid Build Coastguard Worker if (copy_ranges(ap_firmware_file, gvd, ranges))
1010*8617a60dSAndroid Build Coastguard Worker return;
1011*8617a60dSAndroid Build Coastguard Worker
1012*8617a60dSAndroid Build Coastguard Worker if (!ranges->range_count) {
1013*8617a60dSAndroid Build Coastguard Worker printf("No ranges found in the input file\n");
1014*8617a60dSAndroid Build Coastguard Worker } else {
1015*8617a60dSAndroid Build Coastguard Worker printf("Will re-sign the following %zd ranges:\n",
1016*8617a60dSAndroid Build Coastguard Worker ranges->range_count);
1017*8617a60dSAndroid Build Coastguard Worker for (i = 0; i < ranges->range_count; i++) {
1018*8617a60dSAndroid Build Coastguard Worker printf("%08x:%08x\n",
1019*8617a60dSAndroid Build Coastguard Worker ranges->ranges[i].offset,
1020*8617a60dSAndroid Build Coastguard Worker ranges->ranges[i].size);
1021*8617a60dSAndroid Build Coastguard Worker }
1022*8617a60dSAndroid Build Coastguard Worker }
1023*8617a60dSAndroid Build Coastguard Worker }
1024*8617a60dSAndroid Build Coastguard Worker
1025*8617a60dSAndroid Build Coastguard Worker /*
1026*8617a60dSAndroid Build Coastguard Worker * Calculate ranges digest and compare it with the value stored in gvd, with
1027*8617a60dSAndroid Build Coastguard Worker * or without ignoring GBB flags, as requested by the caller.
1028*8617a60dSAndroid Build Coastguard Worker *
1029*8617a60dSAndroid Build Coastguard Worker * @return zero on success, nonzero on failure.
1030*8617a60dSAndroid Build Coastguard Worker */
validate_digest(struct file_buf * ap_firmware_file,const struct gscvd_ro_ranges * ranges,const struct gsc_verification_data * gvd,bool override_gbb_flags)1031*8617a60dSAndroid Build Coastguard Worker static int validate_digest(struct file_buf *ap_firmware_file,
1032*8617a60dSAndroid Build Coastguard Worker const struct gscvd_ro_ranges *ranges,
1033*8617a60dSAndroid Build Coastguard Worker const struct gsc_verification_data *gvd,
1034*8617a60dSAndroid Build Coastguard Worker bool override_gbb_flags)
1035*8617a60dSAndroid Build Coastguard Worker {
1036*8617a60dSAndroid Build Coastguard Worker uint8_t digest[sizeof(gvd->ranges_digest)];
1037*8617a60dSAndroid Build Coastguard Worker
1038*8617a60dSAndroid Build Coastguard Worker if (calculate_ranges_digest(ap_firmware_file, ranges,
1039*8617a60dSAndroid Build Coastguard Worker gvd->hash_alg, digest,
1040*8617a60dSAndroid Build Coastguard Worker sizeof(digest),
1041*8617a60dSAndroid Build Coastguard Worker override_gbb_flags)) {
1042*8617a60dSAndroid Build Coastguard Worker return 1;
1043*8617a60dSAndroid Build Coastguard Worker }
1044*8617a60dSAndroid Build Coastguard Worker
1045*8617a60dSAndroid Build Coastguard Worker return memcmp(digest, gvd->ranges_digest, sizeof(digest));
1046*8617a60dSAndroid Build Coastguard Worker }
1047*8617a60dSAndroid Build Coastguard Worker
1048*8617a60dSAndroid Build Coastguard Worker /*
1049*8617a60dSAndroid Build Coastguard Worker * Validate GVD of the passed in AP firmware file and possibly the root key hash
1050*8617a60dSAndroid Build Coastguard Worker *
1051*8617a60dSAndroid Build Coastguard Worker * The input parameters are the subset of the command line, the first argv
1052*8617a60dSAndroid Build Coastguard Worker * string is the AP firmware file name, the second string, if present, is the
1053*8617a60dSAndroid Build Coastguard Worker * hash of the root public key included in the RO_GSCVD area of the AP
1054*8617a60dSAndroid Build Coastguard Worker * firmware file.
1055*8617a60dSAndroid Build Coastguard Worker *
1056*8617a60dSAndroid Build Coastguard Worker * @return zero on success, nonzero on failure.
1057*8617a60dSAndroid Build Coastguard Worker */
validate_gscvd(int argc,char * argv[])1058*8617a60dSAndroid Build Coastguard Worker static int validate_gscvd(int argc, char *argv[])
1059*8617a60dSAndroid Build Coastguard Worker {
1060*8617a60dSAndroid Build Coastguard Worker struct file_buf ap_firmware_file;
1061*8617a60dSAndroid Build Coastguard Worker int rv;
1062*8617a60dSAndroid Build Coastguard Worker struct gscvd_ro_ranges ranges;
1063*8617a60dSAndroid Build Coastguard Worker struct gsc_verification_data *gvd;
1064*8617a60dSAndroid Build Coastguard Worker const char *file_name;
1065*8617a60dSAndroid Build Coastguard Worker struct vb2_hash root_key_digest = { .algo = VB2_HASH_SHA256 };
1066*8617a60dSAndroid Build Coastguard Worker
1067*8617a60dSAndroid Build Coastguard Worker /* Guaranteed to be available. */
1068*8617a60dSAndroid Build Coastguard Worker file_name = argv[0];
1069*8617a60dSAndroid Build Coastguard Worker
1070*8617a60dSAndroid Build Coastguard Worker if (argc > 1)
1071*8617a60dSAndroid Build Coastguard Worker parse_digest_or_die(root_key_digest.sha256,
1072*8617a60dSAndroid Build Coastguard Worker sizeof(root_key_digest.sha256),
1073*8617a60dSAndroid Build Coastguard Worker argv[1]);
1074*8617a60dSAndroid Build Coastguard Worker
1075*8617a60dSAndroid Build Coastguard Worker do {
1076*8617a60dSAndroid Build Coastguard Worker struct vb2_keyblock *kblock;
1077*8617a60dSAndroid Build Coastguard Worker
1078*8617a60dSAndroid Build Coastguard Worker rv = -1; /* Speculative, will be cleared on success. */
1079*8617a60dSAndroid Build Coastguard Worker
1080*8617a60dSAndroid Build Coastguard Worker if (load_ap_firmware(file_name, &ap_firmware_file, FILE_RO))
1081*8617a60dSAndroid Build Coastguard Worker break;
1082*8617a60dSAndroid Build Coastguard Worker
1083*8617a60dSAndroid Build Coastguard Worker /* Copy ranges from gscvd to local structure. */
1084*8617a60dSAndroid Build Coastguard Worker gvd = (struct gsc_verification_data
1085*8617a60dSAndroid Build Coastguard Worker *)(ap_firmware_file.data +
1086*8617a60dSAndroid Build Coastguard Worker ap_firmware_file.ro_gscvd->area_offset);
1087*8617a60dSAndroid Build Coastguard Worker
1088*8617a60dSAndroid Build Coastguard Worker if (validate_gvd(gvd, &ap_firmware_file))
1089*8617a60dSAndroid Build Coastguard Worker break;
1090*8617a60dSAndroid Build Coastguard Worker
1091*8617a60dSAndroid Build Coastguard Worker if (copy_ranges(&ap_firmware_file, gvd, &ranges))
1092*8617a60dSAndroid Build Coastguard Worker break;
1093*8617a60dSAndroid Build Coastguard Worker
1094*8617a60dSAndroid Build Coastguard Worker /* First try validating without ignoring GBB flags. */
1095*8617a60dSAndroid Build Coastguard Worker if (validate_digest(&ap_firmware_file, &ranges, gvd, false)) {
1096*8617a60dSAndroid Build Coastguard Worker /* It failed, maybe GBB flags are not cleared yet. */
1097*8617a60dSAndroid Build Coastguard Worker if (validate_digest(&ap_firmware_file, &ranges,
1098*8617a60dSAndroid Build Coastguard Worker gvd, true)) {
1099*8617a60dSAndroid Build Coastguard Worker ERROR("Ranges digest mismatch\n");
1100*8617a60dSAndroid Build Coastguard Worker break;
1101*8617a60dSAndroid Build Coastguard Worker }
1102*8617a60dSAndroid Build Coastguard Worker WARN("Ranges digest matches with zeroed GBB flags\n");
1103*8617a60dSAndroid Build Coastguard Worker }
1104*8617a60dSAndroid Build Coastguard Worker
1105*8617a60dSAndroid Build Coastguard Worker /* Find the keyblock. */
1106*8617a60dSAndroid Build Coastguard Worker kblock = (struct vb2_keyblock *)((uintptr_t)gvd + gvd->size);
1107*8617a60dSAndroid Build Coastguard Worker
1108*8617a60dSAndroid Build Coastguard Worker if ((argc > 1) && (vb2_hash_verify(false,
1109*8617a60dSAndroid Build Coastguard Worker vb2_packed_key_data(&gvd->root_key_header),
1110*8617a60dSAndroid Build Coastguard Worker gvd->root_key_header.key_size,
1111*8617a60dSAndroid Build Coastguard Worker &root_key_digest) != VB2_SUCCESS)) {
1112*8617a60dSAndroid Build Coastguard Worker ERROR("Sha256 mismatch\n");
1113*8617a60dSAndroid Build Coastguard Worker break;
1114*8617a60dSAndroid Build Coastguard Worker }
1115*8617a60dSAndroid Build Coastguard Worker
1116*8617a60dSAndroid Build Coastguard Worker if (validate_pubk_signature(&gvd->root_key_header, kblock)) {
1117*8617a60dSAndroid Build Coastguard Worker ERROR("Keyblock not signed by root key\n");
1118*8617a60dSAndroid Build Coastguard Worker break;
1119*8617a60dSAndroid Build Coastguard Worker }
1120*8617a60dSAndroid Build Coastguard Worker
1121*8617a60dSAndroid Build Coastguard Worker if (validate_gvd_signature(gvd, &kblock->data_key)) {
1122*8617a60dSAndroid Build Coastguard Worker ERROR("GVD not signed by platform key\n");
1123*8617a60dSAndroid Build Coastguard Worker break;
1124*8617a60dSAndroid Build Coastguard Worker }
1125*8617a60dSAndroid Build Coastguard Worker
1126*8617a60dSAndroid Build Coastguard Worker rv = 0;
1127*8617a60dSAndroid Build Coastguard Worker } while (false);
1128*8617a60dSAndroid Build Coastguard Worker
1129*8617a60dSAndroid Build Coastguard Worker if (ap_firmware_file.fd != -1)
1130*8617a60dSAndroid Build Coastguard Worker futil_unmap_and_close_file(ap_firmware_file.fd, FILE_RO,
1131*8617a60dSAndroid Build Coastguard Worker ap_firmware_file.data,
1132*8617a60dSAndroid Build Coastguard Worker ap_firmware_file.len);
1133*8617a60dSAndroid Build Coastguard Worker
1134*8617a60dSAndroid Build Coastguard Worker return rv;
1135*8617a60dSAndroid Build Coastguard Worker }
1136*8617a60dSAndroid Build Coastguard Worker
1137*8617a60dSAndroid Build Coastguard Worker /**
1138*8617a60dSAndroid Build Coastguard Worker * Calculate and report sha256 hash of the public key body.
1139*8617a60dSAndroid Build Coastguard Worker *
1140*8617a60dSAndroid Build Coastguard Worker * The hash will be incorporated into GVC firmware to allow it to validate the
1141*8617a60dSAndroid Build Coastguard Worker * root key.
1142*8617a60dSAndroid Build Coastguard Worker *
1143*8617a60dSAndroid Build Coastguard Worker * @param pubk pointer to the public key to process.
1144*8617a60dSAndroid Build Coastguard Worker */
dump_pubk_hash(const struct vb2_packed_key * pubk)1145*8617a60dSAndroid Build Coastguard Worker static void dump_pubk_hash(const struct vb2_packed_key *pubk)
1146*8617a60dSAndroid Build Coastguard Worker {
1147*8617a60dSAndroid Build Coastguard Worker struct vb2_hash hash;
1148*8617a60dSAndroid Build Coastguard Worker size_t i;
1149*8617a60dSAndroid Build Coastguard Worker
1150*8617a60dSAndroid Build Coastguard Worker vb2_hash_calculate(false, vb2_packed_key_data(pubk), pubk->key_size,
1151*8617a60dSAndroid Build Coastguard Worker VB2_HASH_SHA256, &hash);
1152*8617a60dSAndroid Build Coastguard Worker
1153*8617a60dSAndroid Build Coastguard Worker printf("Root key body sha256 hash:\n");
1154*8617a60dSAndroid Build Coastguard Worker
1155*8617a60dSAndroid Build Coastguard Worker for (i = 0; i < sizeof(hash.sha256); i++)
1156*8617a60dSAndroid Build Coastguard Worker printf("%02x", hash.sha256[i]);
1157*8617a60dSAndroid Build Coastguard Worker
1158*8617a60dSAndroid Build Coastguard Worker printf("\n");
1159*8617a60dSAndroid Build Coastguard Worker }
1160*8617a60dSAndroid Build Coastguard Worker
1161*8617a60dSAndroid Build Coastguard Worker /**
1162*8617a60dSAndroid Build Coastguard Worker * The main function of this futilty option.
1163*8617a60dSAndroid Build Coastguard Worker *
1164*8617a60dSAndroid Build Coastguard Worker * See the usage string for input details.
1165*8617a60dSAndroid Build Coastguard Worker *
1166*8617a60dSAndroid Build Coastguard Worker * @return zero on success, nonzero on failure.
1167*8617a60dSAndroid Build Coastguard Worker */
do_gscvd(int argc,char * argv[])1168*8617a60dSAndroid Build Coastguard Worker static int do_gscvd(int argc, char *argv[])
1169*8617a60dSAndroid Build Coastguard Worker {
1170*8617a60dSAndroid Build Coastguard Worker int i;
1171*8617a60dSAndroid Build Coastguard Worker int longindex;
1172*8617a60dSAndroid Build Coastguard Worker bool do_gbb = false;
1173*8617a60dSAndroid Build Coastguard Worker char *infile = NULL;
1174*8617a60dSAndroid Build Coastguard Worker char *outfile = NULL;
1175*8617a60dSAndroid Build Coastguard Worker char *work_file = NULL;
1176*8617a60dSAndroid Build Coastguard Worker struct gscvd_ro_ranges ranges;
1177*8617a60dSAndroid Build Coastguard Worker int errorcount = 0;
1178*8617a60dSAndroid Build Coastguard Worker struct vb2_packed_key *root_pubk = NULL;
1179*8617a60dSAndroid Build Coastguard Worker struct vb2_keyblock *kblock = NULL;
1180*8617a60dSAndroid Build Coastguard Worker struct vb2_private_key *plat_privk = NULL;
1181*8617a60dSAndroid Build Coastguard Worker struct gsc_verification_data *gvd = NULL;
1182*8617a60dSAndroid Build Coastguard Worker struct file_buf ap_firmware_file = { .fd = -1 };
1183*8617a60dSAndroid Build Coastguard Worker uint32_t board_id = UINT32_MAX;
1184*8617a60dSAndroid Build Coastguard Worker char *ro_gscvd_file = NULL;
1185*8617a60dSAndroid Build Coastguard Worker int rv = 0;
1186*8617a60dSAndroid Build Coastguard Worker
1187*8617a60dSAndroid Build Coastguard Worker ranges.range_count = 0;
1188*8617a60dSAndroid Build Coastguard Worker
1189*8617a60dSAndroid Build Coastguard Worker while ((i = getopt_long(argc, argv, short_opts, long_opts,
1190*8617a60dSAndroid Build Coastguard Worker &longindex)) != -1) {
1191*8617a60dSAndroid Build Coastguard Worker switch (i) {
1192*8617a60dSAndroid Build Coastguard Worker case OPT_OUTFILE:
1193*8617a60dSAndroid Build Coastguard Worker outfile = optarg;
1194*8617a60dSAndroid Build Coastguard Worker break;
1195*8617a60dSAndroid Build Coastguard Worker case OPT_RO_GSCVD_FILE:
1196*8617a60dSAndroid Build Coastguard Worker ro_gscvd_file = optarg;
1197*8617a60dSAndroid Build Coastguard Worker break;
1198*8617a60dSAndroid Build Coastguard Worker case 'R':
1199*8617a60dSAndroid Build Coastguard Worker if (parse_ranges(optarg, &ranges)) {
1200*8617a60dSAndroid Build Coastguard Worker ERROR("Could not parse ranges\n");
1201*8617a60dSAndroid Build Coastguard Worker /* Error message has been already printed. */
1202*8617a60dSAndroid Build Coastguard Worker errorcount++;
1203*8617a60dSAndroid Build Coastguard Worker }
1204*8617a60dSAndroid Build Coastguard Worker break;
1205*8617a60dSAndroid Build Coastguard Worker case 'G':
1206*8617a60dSAndroid Build Coastguard Worker do_gbb = true;
1207*8617a60dSAndroid Build Coastguard Worker break;
1208*8617a60dSAndroid Build Coastguard Worker case 'b': {
1209*8617a60dSAndroid Build Coastguard Worker char *e;
1210*8617a60dSAndroid Build Coastguard Worker long long bid;
1211*8617a60dSAndroid Build Coastguard Worker
1212*8617a60dSAndroid Build Coastguard Worker if (strlen(optarg) == 4) {
1213*8617a60dSAndroid Build Coastguard Worker board_id = optarg[0] << 24 |
1214*8617a60dSAndroid Build Coastguard Worker optarg[1] << 16 |
1215*8617a60dSAndroid Build Coastguard Worker optarg[2] << 8 |
1216*8617a60dSAndroid Build Coastguard Worker optarg[3];
1217*8617a60dSAndroid Build Coastguard Worker break;
1218*8617a60dSAndroid Build Coastguard Worker }
1219*8617a60dSAndroid Build Coastguard Worker
1220*8617a60dSAndroid Build Coastguard Worker bid = strtoull(optarg, &e, 16);
1221*8617a60dSAndroid Build Coastguard Worker if (*e || (bid >= UINT32_MAX)) {
1222*8617a60dSAndroid Build Coastguard Worker ERROR("Cannot parse Board ID '%s'\n",
1223*8617a60dSAndroid Build Coastguard Worker optarg);
1224*8617a60dSAndroid Build Coastguard Worker errorcount++;
1225*8617a60dSAndroid Build Coastguard Worker } else {
1226*8617a60dSAndroid Build Coastguard Worker board_id = (uint32_t)bid;
1227*8617a60dSAndroid Build Coastguard Worker }
1228*8617a60dSAndroid Build Coastguard Worker break;
1229*8617a60dSAndroid Build Coastguard Worker }
1230*8617a60dSAndroid Build Coastguard Worker case 'r':
1231*8617a60dSAndroid Build Coastguard Worker root_pubk = vb2_read_packed_key(optarg);
1232*8617a60dSAndroid Build Coastguard Worker if (!root_pubk) {
1233*8617a60dSAndroid Build Coastguard Worker ERROR("Could not read %s\n", optarg);
1234*8617a60dSAndroid Build Coastguard Worker errorcount++;
1235*8617a60dSAndroid Build Coastguard Worker }
1236*8617a60dSAndroid Build Coastguard Worker break;
1237*8617a60dSAndroid Build Coastguard Worker case 'k':
1238*8617a60dSAndroid Build Coastguard Worker kblock = vb2_read_keyblock(optarg);
1239*8617a60dSAndroid Build Coastguard Worker if (!kblock) {
1240*8617a60dSAndroid Build Coastguard Worker ERROR("Could not read %s\n", optarg);
1241*8617a60dSAndroid Build Coastguard Worker errorcount++;
1242*8617a60dSAndroid Build Coastguard Worker }
1243*8617a60dSAndroid Build Coastguard Worker break;
1244*8617a60dSAndroid Build Coastguard Worker case 'p':
1245*8617a60dSAndroid Build Coastguard Worker plat_privk = vb2_read_private_key(optarg);
1246*8617a60dSAndroid Build Coastguard Worker if (!plat_privk) {
1247*8617a60dSAndroid Build Coastguard Worker ERROR("Could not read %s\n", optarg);
1248*8617a60dSAndroid Build Coastguard Worker errorcount++;
1249*8617a60dSAndroid Build Coastguard Worker }
1250*8617a60dSAndroid Build Coastguard Worker break;
1251*8617a60dSAndroid Build Coastguard Worker case 'h':
1252*8617a60dSAndroid Build Coastguard Worker printf("%s", usage);
1253*8617a60dSAndroid Build Coastguard Worker return 0;
1254*8617a60dSAndroid Build Coastguard Worker case '?':
1255*8617a60dSAndroid Build Coastguard Worker if (optopt)
1256*8617a60dSAndroid Build Coastguard Worker ERROR("Unrecognized option: -%c\n", optopt);
1257*8617a60dSAndroid Build Coastguard Worker else
1258*8617a60dSAndroid Build Coastguard Worker ERROR("Unrecognized option: %s\n",
1259*8617a60dSAndroid Build Coastguard Worker argv[optind - 1]);
1260*8617a60dSAndroid Build Coastguard Worker errorcount++;
1261*8617a60dSAndroid Build Coastguard Worker break;
1262*8617a60dSAndroid Build Coastguard Worker case ':':
1263*8617a60dSAndroid Build Coastguard Worker ERROR("Missing argument to -%c\n", optopt);
1264*8617a60dSAndroid Build Coastguard Worker errorcount++;
1265*8617a60dSAndroid Build Coastguard Worker break;
1266*8617a60dSAndroid Build Coastguard Worker case 0: /* handled option */
1267*8617a60dSAndroid Build Coastguard Worker break;
1268*8617a60dSAndroid Build Coastguard Worker default:
1269*8617a60dSAndroid Build Coastguard Worker FATAL("Unrecognized getopt output: %d\n", i);
1270*8617a60dSAndroid Build Coastguard Worker }
1271*8617a60dSAndroid Build Coastguard Worker }
1272*8617a60dSAndroid Build Coastguard Worker
1273*8617a60dSAndroid Build Coastguard Worker if ((optind == 1) && (argc > 1)) {
1274*8617a60dSAndroid Build Coastguard Worker if (ro_gscvd_file) {
1275*8617a60dSAndroid Build Coastguard Worker ERROR("Unexpected --gscvd_out in command line\n");
1276*8617a60dSAndroid Build Coastguard Worker goto usage_out;
1277*8617a60dSAndroid Build Coastguard Worker }
1278*8617a60dSAndroid Build Coastguard Worker /* This must be a validation request. */
1279*8617a60dSAndroid Build Coastguard Worker return validate_gscvd(argc - 1, argv + 1);
1280*8617a60dSAndroid Build Coastguard Worker }
1281*8617a60dSAndroid Build Coastguard Worker
1282*8617a60dSAndroid Build Coastguard Worker if (errorcount) /* Error message(s) should have been printed by now. */
1283*8617a60dSAndroid Build Coastguard Worker goto usage_out;
1284*8617a60dSAndroid Build Coastguard Worker
1285*8617a60dSAndroid Build Coastguard Worker if (!root_pubk) {
1286*8617a60dSAndroid Build Coastguard Worker ERROR("Missing --root_pub_key argument\n");
1287*8617a60dSAndroid Build Coastguard Worker goto usage_out;
1288*8617a60dSAndroid Build Coastguard Worker } else if (argc == 3) {
1289*8617a60dSAndroid Build Coastguard Worker if (ro_gscvd_file) {
1290*8617a60dSAndroid Build Coastguard Worker ERROR("Unexpected --gscvd_out in command line\n");
1291*8617a60dSAndroid Build Coastguard Worker goto usage_out;
1292*8617a60dSAndroid Build Coastguard Worker }
1293*8617a60dSAndroid Build Coastguard Worker /*
1294*8617a60dSAndroid Build Coastguard Worker * This is a request to print out the hash of the root pub key
1295*8617a60dSAndroid Build Coastguard Worker * payload.
1296*8617a60dSAndroid Build Coastguard Worker */
1297*8617a60dSAndroid Build Coastguard Worker dump_pubk_hash(root_pubk);
1298*8617a60dSAndroid Build Coastguard Worker return 0;
1299*8617a60dSAndroid Build Coastguard Worker }
1300*8617a60dSAndroid Build Coastguard Worker
1301*8617a60dSAndroid Build Coastguard Worker if (optind != (argc - 1)) {
1302*8617a60dSAndroid Build Coastguard Worker ERROR("Misformatted command line\n");
1303*8617a60dSAndroid Build Coastguard Worker goto usage_out;
1304*8617a60dSAndroid Build Coastguard Worker }
1305*8617a60dSAndroid Build Coastguard Worker
1306*8617a60dSAndroid Build Coastguard Worker infile = argv[optind];
1307*8617a60dSAndroid Build Coastguard Worker
1308*8617a60dSAndroid Build Coastguard Worker if (!kblock) {
1309*8617a60dSAndroid Build Coastguard Worker ERROR("Missing --keyblock argument\n");
1310*8617a60dSAndroid Build Coastguard Worker goto usage_out;
1311*8617a60dSAndroid Build Coastguard Worker }
1312*8617a60dSAndroid Build Coastguard Worker
1313*8617a60dSAndroid Build Coastguard Worker if (!plat_privk) {
1314*8617a60dSAndroid Build Coastguard Worker ERROR("Missing --platform_priv argument\n");
1315*8617a60dSAndroid Build Coastguard Worker goto usage_out;
1316*8617a60dSAndroid Build Coastguard Worker }
1317*8617a60dSAndroid Build Coastguard Worker
1318*8617a60dSAndroid Build Coastguard Worker if (board_id == UINT32_MAX) {
1319*8617a60dSAndroid Build Coastguard Worker ERROR("Missing --board_id argument\n");
1320*8617a60dSAndroid Build Coastguard Worker goto usage_out;
1321*8617a60dSAndroid Build Coastguard Worker }
1322*8617a60dSAndroid Build Coastguard Worker
1323*8617a60dSAndroid Build Coastguard Worker if (outfile) {
1324*8617a60dSAndroid Build Coastguard Worker if (futil_copy_file(infile, outfile) < 0)
1325*8617a60dSAndroid Build Coastguard Worker exit(1);
1326*8617a60dSAndroid Build Coastguard Worker work_file = outfile;
1327*8617a60dSAndroid Build Coastguard Worker } else {
1328*8617a60dSAndroid Build Coastguard Worker work_file = infile;
1329*8617a60dSAndroid Build Coastguard Worker }
1330*8617a60dSAndroid Build Coastguard Worker
1331*8617a60dSAndroid Build Coastguard Worker do {
1332*8617a60dSAndroid Build Coastguard Worker rv = 1; /* Speculative, will be cleared on success. */
1333*8617a60dSAndroid Build Coastguard Worker
1334*8617a60dSAndroid Build Coastguard Worker if (validate_pubk_signature(root_pubk, kblock))
1335*8617a60dSAndroid Build Coastguard Worker break;
1336*8617a60dSAndroid Build Coastguard Worker
1337*8617a60dSAndroid Build Coastguard Worker if (validate_privk(kblock, plat_privk))
1338*8617a60dSAndroid Build Coastguard Worker break;
1339*8617a60dSAndroid Build Coastguard Worker
1340*8617a60dSAndroid Build Coastguard Worker if (load_ap_firmware(work_file, &ap_firmware_file, FILE_RW))
1341*8617a60dSAndroid Build Coastguard Worker break;
1342*8617a60dSAndroid Build Coastguard Worker
1343*8617a60dSAndroid Build Coastguard Worker if (!ranges.range_count)
1344*8617a60dSAndroid Build Coastguard Worker try_retrieving_ranges_from_the_image(infile,
1345*8617a60dSAndroid Build Coastguard Worker &ranges,
1346*8617a60dSAndroid Build Coastguard Worker &ap_firmware_file);
1347*8617a60dSAndroid Build Coastguard Worker
1348*8617a60dSAndroid Build Coastguard Worker if (!ranges.range_count && !do_gbb) {
1349*8617a60dSAndroid Build Coastguard Worker ERROR("Missing --ranges argument and no ranges in the input file\n");
1350*8617a60dSAndroid Build Coastguard Worker break;
1351*8617a60dSAndroid Build Coastguard Worker }
1352*8617a60dSAndroid Build Coastguard Worker
1353*8617a60dSAndroid Build Coastguard Worker if (do_gbb && add_gbb(&ranges, &ap_firmware_file))
1354*8617a60dSAndroid Build Coastguard Worker break;
1355*8617a60dSAndroid Build Coastguard Worker
1356*8617a60dSAndroid Build Coastguard Worker if (verify_ranges(&ranges, &ap_firmware_file))
1357*8617a60dSAndroid Build Coastguard Worker break;
1358*8617a60dSAndroid Build Coastguard Worker
1359*8617a60dSAndroid Build Coastguard Worker gvd = create_gvd(&ap_firmware_file, &ranges,
1360*8617a60dSAndroid Build Coastguard Worker root_pubk, plat_privk, board_id);
1361*8617a60dSAndroid Build Coastguard Worker if (!gvd)
1362*8617a60dSAndroid Build Coastguard Worker break;
1363*8617a60dSAndroid Build Coastguard Worker
1364*8617a60dSAndroid Build Coastguard Worker if (fill_gvd_area(&ap_firmware_file, gvd,
1365*8617a60dSAndroid Build Coastguard Worker kblock, ro_gscvd_file))
1366*8617a60dSAndroid Build Coastguard Worker break;
1367*8617a60dSAndroid Build Coastguard Worker
1368*8617a60dSAndroid Build Coastguard Worker rv = 0;
1369*8617a60dSAndroid Build Coastguard Worker } while (false);
1370*8617a60dSAndroid Build Coastguard Worker
1371*8617a60dSAndroid Build Coastguard Worker free(gvd);
1372*8617a60dSAndroid Build Coastguard Worker free(root_pubk);
1373*8617a60dSAndroid Build Coastguard Worker free(kblock);
1374*8617a60dSAndroid Build Coastguard Worker vb2_free_private_key(plat_privk);
1375*8617a60dSAndroid Build Coastguard Worker
1376*8617a60dSAndroid Build Coastguard Worker if (ap_firmware_file.fd != -1)
1377*8617a60dSAndroid Build Coastguard Worker futil_unmap_and_close_file(ap_firmware_file.fd, FILE_RW,
1378*8617a60dSAndroid Build Coastguard Worker ap_firmware_file.data,
1379*8617a60dSAndroid Build Coastguard Worker ap_firmware_file.len);
1380*8617a60dSAndroid Build Coastguard Worker
1381*8617a60dSAndroid Build Coastguard Worker return rv;
1382*8617a60dSAndroid Build Coastguard Worker
1383*8617a60dSAndroid Build Coastguard Worker usage_out:
1384*8617a60dSAndroid Build Coastguard Worker fputs(usage, stderr);
1385*8617a60dSAndroid Build Coastguard Worker return 1;
1386*8617a60dSAndroid Build Coastguard Worker }
1387*8617a60dSAndroid Build Coastguard Worker
1388*8617a60dSAndroid Build Coastguard Worker DECLARE_FUTIL_COMMAND(gscvd, do_gscvd, VBOOT_VERSION_2_1,
1389*8617a60dSAndroid Build Coastguard Worker "Create RO verification structure");
1390