File: | 3rdparty/vboot/futility/cmd_vbutil_firmware.c |
Warning: | line 268, column 2 Value stored to 'now' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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((void*)0), 0, 0, 0} |
52 | }; |
53 | |
54 | /* Print help and return error */ |
55 | static void print_help(int argc, char *argv[]) |
56 | { |
57 | printf("\nUsage: " MYNAME"futility" " %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 */ |
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((void*)0); |
90 | struct vb2_private_key *signing_key = NULL((void*)0); |
91 | struct vb2_packed_key *kernel_subkey = NULL((void*)0); |
92 | struct vb2_signature *body_sig = NULL((void*)0); |
93 | struct vb2_fw_preamble *preamble = NULL((void*)0); |
94 | uint8_t *fv_data = NULL((void*)0); |
95 | int retval = 1; |
96 | |
97 | if (!outfile) { |
98 | FATAL("Must specify output filename\n")do { fprintf(stderr, "FATAL: %s: " "Must specify output filename\n" , __func__ ); exit(1); } while (0); |
99 | goto vblock_cleanup; |
100 | } |
101 | if (!keyblock_file || !signprivate || !kernelkey_file) { |
102 | FATAL("Must specify all keys\n")do { fprintf(stderr, "FATAL: %s: " "Must specify all keys\n", __func__ ); exit(1); } while (0); |
103 | goto vblock_cleanup; |
104 | } |
105 | if (!fv_file) { |
106 | FATAL("Must specify firmware volume\n")do { fprintf(stderr, "FATAL: %s: " "Must specify firmware volume\n" , __func__ ); exit(1); } while (0); |
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")do { fprintf(stderr, "FATAL: %s: " "Error reading keyblock.\n" , __func__ ); exit(1); } while (0); |
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")do { fprintf(stderr, "FATAL: %s: " "Error reading signing key.\n" , __func__ ); exit(1); } while (0); |
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")do { fprintf(stderr, "FATAL: %s: " "Error reading kernel subkey.\n" , __func__ ); exit(1); } while (0); |
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")do { fprintf(stderr, "FATAL: %s: " "Empty firmware volume file\n" , __func__ ); exit(1); } while (0); |
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")do { fprintf(stderr, "FATAL: %s: " "Error calculating body signature\n" , __func__ ); exit(1); } while (0); |
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")do { fprintf(stderr, "FATAL: %s: " "Error creating preamble.\n" , __func__ ); exit(1); } while (0); |
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)do { fprintf(stderr, "FATAL: %s: " "Can't open output file %s\n" , __func__, outfile ); exit(1); } while (0); |
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)do { fprintf(stderr, "FATAL: %s: " "Can't write output file %s\n" , __func__, outfile ); exit(1); } while (0); |
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 | |
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(12 * 1024)] |
190 | __attribute__((aligned(VB2_WORKBUF_ALIGN8))); |
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((void*)0); |
197 | uint8_t *blob = NULL((void*)0); |
198 | uint8_t *fv_data = NULL((void*)0); |
199 | int retval = 1; |
200 | |
201 | if (!infile || !signpubkey || !fv_file) { |
202 | FATAL("Must specify filename, signpubkey, and fv\n")do { fprintf(stderr, "FATAL: %s: " "Must specify filename, signpubkey, and fv\n" , __func__ ); exit(1); } while (0); |
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")fprintf(stderr, "ERROR: %s: " "Reading signpubkey.\n", __func__ ); |
211 | goto verify_cleanup; |
212 | } |
213 | if (VB2_SUCCESS != vb2_unpack_key_buffer(&sign_key, pubkbuf, pubklen)) { |
214 | ERROR("Unpacking signpubkey.\n")fprintf(stderr, "ERROR: %s: " "Unpacking signpubkey.\n", __func__ ); |
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")do { fprintf(stderr, "FATAL: %s: " "Error reading input file\n" , __func__ ); exit(1); } while (0); |
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")do { fprintf(stderr, "FATAL: %s: " "Error reading firmware volume\n" , __func__ ); exit(1); } while (0); |
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")do { fprintf(stderr, "FATAL: %s: " "Error verifying keyblock.\n" , __func__ ); exit(1); } while (0); |
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")fprintf(stderr, "ERROR: %s: " "Parsing data key.\n", __func__ ); |
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")do { fprintf(stderr, "FATAL: %s: " "Error2 verifying preamble.\n" , __func__ ); exit(1); } while (0); |
266 | goto verify_cleanup; |
267 | } |
268 | now += pre2->preamble_size; |
Value stored to 'now' is never read | |
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_NORMAL0x00000001) { |
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"do { fprintf(stderr, "FATAL: %s: " "Metadata hash verification not supported.\n" "Please use `futility verify BIOS_IMAGE`.\n", __func__ ); exit (1); } while (0) |
299 | "Please use `futility verify BIOS_IMAGE`.\n")do { fprintf(stderr, "FATAL: %s: " "Metadata hash verification not supported.\n" "Please use `futility verify BIOS_IMAGE`.\n", __func__ ); exit (1); } while (0); |
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")do { fprintf(stderr, "FATAL: %s: " "Error verifying firmware body.\n" , __func__ ); exit(1); } while (0); |
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")do { fprintf(stderr, "FATAL: %s: " "Unable to write kernel subkey\n" , __func__ ); exit(1); } while (0); |
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 | |
331 | static int do_vbutil_firmware(int argc, char *argv[]) |
332 | { |
333 | |
334 | char *filename = NULL((void*)0); |
335 | char *keyblock_file = NULL((void*)0); |
336 | char *signpubkey = NULL((void*)0); |
337 | char *signprivate = NULL((void*)0); |
338 | uint32_t version = 0; |
339 | char *fv_file = NULL((void*)0); |
340 | char *kernelkey_file = NULL((void*)0); |
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((void*)0))) != -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")fprintf(stderr, "ERROR: %s: " "Must specify a mode.\n", __func__ ); |
415 | print_help(argc, argv); |
416 | return 1; |
417 | } |
418 | } |
419 | |
420 | DECLARE_FUTIL_COMMAND(vbutil_firmware, do_vbutil_firmware, VBOOT_VERSION_1_0,const struct futil_cmd_t __cmd_vbutil_firmware = { .name = "vbutil_firmware" , .handler = do_vbutil_firmware, .version = VBOOT_VERSION_1_0 , .shorthelp = "Verified boot firmware utility", } |
421 | "Verified boot firmware utility")const struct futil_cmd_t __cmd_vbutil_firmware = { .name = "vbutil_firmware" , .handler = do_vbutil_firmware, .version = VBOOT_VERSION_1_0 , .shorthelp = "Verified boot firmware utility", }; |