xref: /aosp_15_r20/external/vboot_reference/futility/cmd_vbutil_firmware.c (revision 8617a60d3594060b7ecbd21bc622a7c14f3cf2bc)
1 /* Copyright 2011 The ChromiumOS Authors
2  * Use of this source code is governed by a BSD-style license that can be
3  * found in the LICENSE file.
4  *
5  * Verified boot firmware utility
6  */
7 
8 #include <getopt.h>
9 #include <inttypes.h>		/* For PRIu64 */
10 #include <stddef.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <unistd.h>
14 
15 #include "2api.h"
16 #include "2common.h"
17 #include "2rsa.h"
18 #include "2sysincludes.h"
19 #include "futility.h"
20 #include "host_common.h"
21 #include "host_key21.h"
22 #include "kernel_blob.h"
23 #include "util_misc.h"
24 #include "vb1_helper.h"
25 
26 /* Command line options */
27 enum {
28 	OPT_MODE_VBLOCK = 1000,
29 	OPT_MODE_VERIFY,
30 	OPT_KEYBLOCK,
31 	OPT_SIGNPUBKEY,
32 	OPT_SIGNPRIVATE,
33 	OPT_VERSION,
34 	OPT_FV,
35 	OPT_KERNELKEY,
36 	OPT_FLAGS,
37 	OPT_HELP,
38 };
39 
40 static const struct option long_opts[] = {
41 	{"vblock", 1, 0, OPT_MODE_VBLOCK},
42 	{"verify", 1, 0, OPT_MODE_VERIFY},
43 	{"keyblock", 1, 0, OPT_KEYBLOCK},
44 	{"signpubkey", 1, 0, OPT_SIGNPUBKEY},
45 	{"signprivate", 1, 0, OPT_SIGNPRIVATE},
46 	{"version", 1, 0, OPT_VERSION},
47 	{"fv", 1, 0, OPT_FV},
48 	{"kernelkey", 1, 0, OPT_KERNELKEY},
49 	{"flags", 1, 0, OPT_FLAGS},
50 	{"help", 0, 0, OPT_HELP},
51 	{NULL, 0, 0, 0}
52 };
53 
54 /* Print help and return error */
print_help(int argc,char * argv[])55 static void print_help(int argc, char *argv[])
56 {
57 	printf("\nUsage:  " MYNAME " %s <--vblock|--verify> <file> [OPTIONS]\n"
58 	       "\n"
59 	       "For '--vblock <file>', required OPTIONS are:\n"
60 	       "\n"
61 	       "  --keyblock <file>           Keyblock in .keyblock format\n"
62 	       "  --signprivate <file>"
63 	       "        Signing private key in .vbprivk format\n"
64 	       "  --version <number>          Firmware version\n"
65 	       "  --fv <file>                 Firmware volume to sign\n"
66 	       "  --kernelkey <file>          Kernel subkey in .vbpubk format\n"
67 	       "\n"
68 	       "optional OPTIONS are:\n"
69 	       "  --flags <number>            Preamble flags (defaults to 0)\n"
70 	       "\n"
71 	       "For '--verify <file>', required OPTIONS are:\n"
72 	       "\n"
73 	       "  --signpubkey <file>"
74 	       "         Signing public key in .vbpubk format\n"
75 	       "  --fv <file>                 Firmware volume to verify\n"
76 	       "\n"
77 	       "For '--verify <file>', optional OPTIONS are:\n"
78 	       "  --kernelkey <file>"
79 	       "          Write the kernel subkey to this file\n\n",
80 	       argv[0]);
81 }
82 
83 /* Create a firmware .vblock */
do_vblock(const char * outfile,const char * keyblock_file,const char * signprivate,uint32_t version,const char * fv_file,const char * kernelkey_file,uint32_t preamble_flags)84 static int do_vblock(const char *outfile, const char *keyblock_file,
85 		     const char *signprivate, uint32_t version,
86 		     const char *fv_file, const char *kernelkey_file,
87 		     uint32_t preamble_flags)
88 {
89 	struct vb2_keyblock *keyblock = NULL;
90 	struct vb2_private_key *signing_key = NULL;
91 	struct vb2_packed_key *kernel_subkey = NULL;
92 	struct vb2_signature *body_sig = NULL;
93 	struct vb2_fw_preamble *preamble = NULL;
94 	uint8_t *fv_data = NULL;
95 	int retval = 1;
96 
97 	if (!outfile) {
98 		FATAL("Must specify output filename\n");
99 		goto vblock_cleanup;
100 	}
101 	if (!keyblock_file || !signprivate || !kernelkey_file) {
102 		FATAL("Must specify all keys\n");
103 		goto vblock_cleanup;
104 	}
105 	if (!fv_file) {
106 		FATAL("Must specify firmware volume\n");
107 		goto vblock_cleanup;
108 	}
109 
110 	/* Read the keyblock and keys */
111 	keyblock = vb2_read_keyblock(keyblock_file);
112 	if (!keyblock) {
113 		FATAL("Error reading keyblock.\n");
114 		goto vblock_cleanup;
115 	}
116 
117 	signing_key = vb2_read_private_key(signprivate);
118 	if (!signing_key) {
119 		FATAL("Error reading signing key.\n");
120 		goto vblock_cleanup;
121 	}
122 
123 	kernel_subkey = vb2_read_packed_key(kernelkey_file);
124 	if (!kernel_subkey) {
125 		FATAL("Error reading kernel subkey.\n");
126 		goto vblock_cleanup;
127 	}
128 
129 	/* Read and sign the firmware volume */
130 	uint32_t fv_size;
131 	if (VB2_SUCCESS != vb2_read_file(fv_file, &fv_data, &fv_size))
132 		goto vblock_cleanup;
133 	if (!fv_size) {
134 		FATAL("Empty firmware volume file\n");
135 		goto vblock_cleanup;
136 	}
137 	body_sig = vb2_calculate_signature(fv_data, fv_size, signing_key);
138 	if (!body_sig) {
139 		FATAL("Error calculating body signature\n");
140 		goto vblock_cleanup;
141 	}
142 
143 	/* Create preamble */
144 	preamble = vb2_create_fw_preamble(version, kernel_subkey, body_sig,
145 					  signing_key, preamble_flags);
146 	if (!preamble) {
147 		FATAL("Error creating preamble.\n");
148 		goto vblock_cleanup;
149 	}
150 
151 	/* Write the output file */
152 	FILE *f = fopen(outfile, "wb");
153 	if (!f) {
154 		FATAL("Can't open output file %s\n", outfile);
155 		goto vblock_cleanup;
156 	}
157 	int i = ((1 != fwrite(keyblock, keyblock->keyblock_size, 1, f)) ||
158 		 (1 != fwrite(preamble, preamble->preamble_size, 1, f)));
159 	fclose(f);
160 	if (i) {
161 		FATAL("Can't write output file %s\n", outfile);
162 		unlink(outfile);
163 		goto vblock_cleanup;
164 	}
165 
166 	/* Success */
167 	retval = 0;
168 
169 vblock_cleanup:
170 	if (keyblock)
171 		free(keyblock);
172 	if (signing_key)
173 		free(signing_key);
174 	if (kernel_subkey)
175 		free(kernel_subkey);
176 	if (fv_data)
177 		free(fv_data);
178 	if (body_sig)
179 		free(body_sig);
180 	if (preamble)
181 		free(preamble);
182 
183 	return retval;
184 }
185 
do_verify(const char * infile,const char * signpubkey,const char * fv_file,const char * kernelkey_file)186 static int do_verify(const char *infile, const char *signpubkey,
187 		     const char *fv_file, const char *kernelkey_file)
188 {
189 	uint8_t workbuf[VB2_FIRMWARE_WORKBUF_RECOMMENDED_SIZE]
190 		__attribute__((aligned(VB2_WORKBUF_ALIGN)));
191 	struct vb2_workbuf wb;
192 	vb2_workbuf_init(&wb, workbuf, sizeof(workbuf));
193 
194 	uint32_t now = 0;
195 
196 	uint8_t *pubkbuf = NULL;
197 	uint8_t *blob = NULL;
198 	uint8_t *fv_data = NULL;
199 	int retval = 1;
200 
201 	if (!infile || !signpubkey || !fv_file) {
202 		FATAL("Must specify filename, signpubkey, and fv\n");
203 		goto verify_cleanup;
204 	}
205 
206 	/* Read public signing key */
207 	uint32_t pubklen;
208 	struct vb2_public_key sign_key;
209 	if (VB2_SUCCESS != vb2_read_file(signpubkey, &pubkbuf, &pubklen)) {
210 		ERROR("Reading signpubkey.\n");
211 		goto verify_cleanup;
212 	}
213 	if (VB2_SUCCESS != vb2_unpack_key_buffer(&sign_key, pubkbuf, pubklen)) {
214 		ERROR("Unpacking signpubkey.\n");
215 		goto verify_cleanup;
216 	}
217 
218 	/* Read blob */
219 	uint32_t blob_size;
220 	if (VB2_SUCCESS != vb2_read_file(infile, &blob, &blob_size)) {
221 		FATAL("Error reading input file\n");
222 		goto verify_cleanup;
223 	}
224 
225 	/* Read firmware volume */
226 	uint32_t fv_size;
227 	if (VB2_SUCCESS != vb2_read_file(fv_file, &fv_data, &fv_size)) {
228 		FATAL("Error reading firmware volume\n");
229 		goto verify_cleanup;
230 	}
231 
232 	/* Verify keyblock */
233 	struct vb2_keyblock *keyblock = (struct vb2_keyblock *)blob;
234 	if (VB2_SUCCESS !=
235 	    vb2_verify_keyblock(keyblock, blob_size, &sign_key, &wb)) {
236 		FATAL("Error verifying keyblock.\n");
237 		goto verify_cleanup;
238 	}
239 
240 	now += keyblock->keyblock_size;
241 
242 	printf("Keyblock:\n");
243 	printf("  Size:                %d\n", keyblock->keyblock_size);
244 	printf("  Flags:               %d (ignored)\n",
245 	       keyblock->keyblock_flags);
246 
247 	struct vb2_packed_key *packed_key = &keyblock->data_key;
248 	printf("  Data key algorithm:  %d %s\n", packed_key->algorithm,
249 	       vb2_get_crypto_algorithm_name(packed_key->algorithm));
250 	printf("  Data key version:    %d\n", packed_key->key_version);
251 	printf("  Data key sha1sum:    %s\n",
252 	       packed_key_sha1_string(packed_key));
253 
254 	struct vb2_public_key data_key;
255 	if (VB2_SUCCESS !=
256 	    vb2_unpack_key(&data_key, &keyblock->data_key)) {
257 		ERROR("Parsing data key.\n");
258 		goto verify_cleanup;
259 	}
260 
261 	/* Verify preamble */
262 	struct vb2_fw_preamble *pre2 = (struct vb2_fw_preamble *)(blob + now);
263 	if (VB2_SUCCESS !=
264 	    vb2_verify_fw_preamble(pre2, blob_size - now, &data_key, &wb)) {
265 		FATAL("Error2 verifying preamble.\n");
266 		goto verify_cleanup;
267 	}
268 	now += pre2->preamble_size;
269 
270 	uint32_t flags = pre2->flags;
271 	if (pre2->header_version_minor < 1)
272 		flags = 0;  /* Old 2.0 structure didn't have flags */
273 
274 	printf("Preamble:\n");
275 	printf("  Size:                  %d\n", pre2->preamble_size);
276 	printf("  Header version:        %d.%d\n",
277 	       pre2->header_version_major, pre2->header_version_minor);
278 	printf("  Firmware version:      %d\n", pre2->firmware_version);
279 
280 	struct vb2_packed_key *kernel_subkey = &pre2->kernel_subkey;
281 	printf("  Kernel key algorithm:  %d %s\n", kernel_subkey->algorithm,
282 	       vb2_get_crypto_algorithm_name(kernel_subkey->algorithm));
283 	printf("  Kernel key version:    %d\n", kernel_subkey->key_version);
284 	printf("  Kernel key sha1sum:    %s\n",
285 	       packed_key_sha1_string(kernel_subkey));
286 	printf("  Firmware body size:    %d\n", pre2->body_signature.data_size);
287 	printf("  Preamble flags:        %d\n", flags);
288 
289 	/* TODO: verify body size same as signature size */
290 
291 	/* Verify body */
292 	if (flags & VB2_FIRMWARE_PREAMBLE_USE_RO_NORMAL) {
293 		printf("Preamble requests USE_RO_NORMAL;"
294 		       " skipping body verification.\n");
295 	} else if (!pre2->body_signature.data_size) {
296 		/* cbfstool needs the whole firmware image to get the
297 		   metadata hash */
298 		FATAL("Metadata hash verification not supported.\n"
299 		      "Please use `futility verify BIOS_IMAGE`.\n");
300 		goto verify_cleanup;
301 	} else if (VB2_SUCCESS ==
302 		   vb2_verify_data(fv_data, fv_size, &pre2->body_signature,
303 				   &data_key, &wb)) {
304 		printf("Body verification succeeded.\n");
305 	} else {
306 		FATAL("Error verifying firmware body.\n");
307 		goto verify_cleanup;
308 	}
309 
310 	if (kernelkey_file &&
311 	    VB2_SUCCESS != vb2_write_packed_key(kernelkey_file,
312 						kernel_subkey)) {
313 		FATAL("Unable to write kernel subkey\n");
314 		goto verify_cleanup;
315 	}
316 
317 	/* Success */
318 	retval = 0;
319 
320 verify_cleanup:
321 	if (pubkbuf)
322 		free(pubkbuf);
323 	if (blob)
324 		free(blob);
325 	if (fv_data)
326 		free(fv_data);
327 
328 	return retval;
329 }
330 
do_vbutil_firmware(int argc,char * argv[])331 static int do_vbutil_firmware(int argc, char *argv[])
332 {
333 
334 	char *filename = NULL;
335 	char *keyblock_file = NULL;
336 	char *signpubkey = NULL;
337 	char *signprivate = NULL;
338 	uint32_t version = 0;
339 	char *fv_file = NULL;
340 	char *kernelkey_file = NULL;
341 	uint32_t preamble_flags = 0;
342 	int mode = 0;
343 	int parse_error = 0;
344 	char *e;
345 	int i;
346 
347 	while ((i = getopt_long(argc, argv, "", long_opts, NULL)) != -1) {
348 		switch (i) {
349 		case '?':
350 			/* Unhandled option */
351 			printf("Unknown option\n");
352 			parse_error = 1;
353 			break;
354 		case OPT_HELP:
355 			print_help(argc, argv);
356 			return !!parse_error;
357 
358 		case OPT_MODE_VBLOCK:
359 		case OPT_MODE_VERIFY:
360 			mode = i;
361 			filename = optarg;
362 			break;
363 
364 		case OPT_KEYBLOCK:
365 			keyblock_file = optarg;
366 			break;
367 
368 		case OPT_SIGNPUBKEY:
369 			signpubkey = optarg;
370 			break;
371 
372 		case OPT_SIGNPRIVATE:
373 			signprivate = optarg;
374 			break;
375 
376 		case OPT_FV:
377 			fv_file = optarg;
378 			break;
379 
380 		case OPT_KERNELKEY:
381 			kernelkey_file = optarg;
382 			break;
383 
384 		case OPT_VERSION:
385 			version = strtoul(optarg, &e, 0);
386 			if (!*optarg || (e && *e)) {
387 				printf("Invalid --version\n");
388 				parse_error = 1;
389 			}
390 			break;
391 
392 		case OPT_FLAGS:
393 			preamble_flags = strtoul(optarg, &e, 0);
394 			if (!*optarg || (e && *e)) {
395 				printf("Invalid --flags\n");
396 				parse_error = 1;
397 			}
398 			break;
399 		}
400 	}
401 
402 	if (parse_error) {
403 		print_help(argc, argv);
404 		return 1;
405 	}
406 
407 	switch (mode) {
408 	case OPT_MODE_VBLOCK:
409 		return do_vblock(filename, keyblock_file, signprivate, version,
410 				 fv_file, kernelkey_file, preamble_flags);
411 	case OPT_MODE_VERIFY:
412 		return do_verify(filename, signpubkey, fv_file, kernelkey_file);
413 	default:
414 		ERROR("Must specify a mode.\n");
415 		print_help(argc, argv);
416 		return 1;
417 	}
418 }
419 
420 DECLARE_FUTIL_COMMAND(vbutil_firmware, do_vbutil_firmware, VBOOT_VERSION_1_0,
421 		      "Verified boot firmware utility");
422