blob: 8c59fb21527a0c02ff42d10befa0e50be0333de2 [file] [log] [blame]
Bill Richardson15dc6fc2014-09-02 14:45:44 -07001/*
2 * Copyright 2014 The Chromium OS Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
5 */
6#include <errno.h>
7#include <fcntl.h>
8#include <getopt.h>
9#include <inttypes.h>
10#include <limits.h>
11#include <stddef.h>
12#include <stdint.h>
13#include <stdio.h>
14#include <stdlib.h>
15#include <string.h>
16#include <sys/stat.h>
17#include <sys/types.h>
18#include <unistd.h>
19
20#include "bmpblk_header.h"
21#include "fmap.h"
22#include "futility.h"
23#include "gbb_header.h"
24#include "host_common.h"
25#include "traversal.h"
26#include "util_misc.h"
27#include "vboot_common.h"
28
29/* Local values for cb_area_s._flags */
30enum callback_flags {
31 AREA_IS_VALID = 0x00000001,
32};
33
34/* Local structure for args, etc. */
35struct local_data_s {
36 VbPrivateKey *signprivate;
37 VbKeyBlockHeader *keyblock;
38 VbPublicKey *kernel_subkey;
39 VbPrivateKey *devsignprivate;
40 VbKeyBlockHeader *devkeyblock;
41 uint32_t version;
42 uint32_t flags;
Bill Richardsona19b00d2014-09-04 23:20:43 -070043 int flags_specified;
Bill Richardson15dc6fc2014-09-02 14:45:44 -070044 char *loemdir;
45 char *loemid;
46} option = {
47 .version = 1,
48};
49
50
51int futil_cb_sign_bogus(struct futil_traverse_state_s *state)
52{
53 fprintf(stderr, "Don't know how to sign %s\n", state->name);
54 return 1;
55}
56
57int futil_cb_sign_notyet(struct futil_traverse_state_s *state)
58{
59 fprintf(stderr, "Signing %s is not yet implemented\n", state->name);
60 return 1;
61}
62
63/*
64 * This handles FW_MAIN_A and FW_MAIN_B while processing a BIOS image.
65 *
66 * The data in state->my_area is just the RW firmware blob, so there's nothing
67 * useful to show about it. We'll just mark it as present so when we encounter
68 * corresponding VBLOCK area, we'll have this to verify.
69 */
70int futil_cb_sign_fw_main(struct futil_traverse_state_s *state)
71{
72 state->my_area->_flags |= AREA_IS_VALID;
73 return 0;
74}
75
76
77int futil_cb_sign_fw_preamble(struct futil_traverse_state_s *state)
78{
79 VbKeyBlockHeader *key_block = (VbKeyBlockHeader *)state->my_area->buf;
Bill Richardsone0519752014-09-03 14:20:10 -070080 uint32_t len = state->my_area->len;
Bill Richardson15dc6fc2014-09-02 14:45:44 -070081
82 /* We don't (yet) handle standalone VBLOCKs */
83 if (state->component == CB_FW_PREAMBLE)
84 return futil_cb_sign_notyet(state);
85
Bill Richardsone0519752014-09-03 14:20:10 -070086 /*
87 * If we have a valid keyblock and fw_preamble, then we can use them to
88 * determine the size of the firmware body. Otherwise, we'll have to
89 * just sign the whole region.
90 */
91 if (VBOOT_SUCCESS != KeyBlockVerify(key_block, len, NULL, 1)) {
92 fprintf(stderr, "Warning: %s keyblock is invalid. "
93 "Signing the entire FW FMAP region...\n",
94 state->name);
95 goto whatever;
96 }
97
98 RSAPublicKey *rsa = PublicKeyToRSA(&key_block->data_key);
99 if (!rsa) {
100 fprintf(stderr, "Warning: %s public key is invalid. "
101 "Signing the entire FW FMAP region...\n",
102 state->name);
103 goto whatever;
104 }
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700105 uint32_t more = key_block->key_block_size;
106 VbFirmwarePreambleHeader *preamble =
107 (VbFirmwarePreambleHeader *)(state->my_area->buf + more);
108 uint32_t fw_size = preamble->body_signature.data_size;
Bill Richardsone0519752014-09-03 14:20:10 -0700109 struct cb_area_s *fw_body_area = 0;
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700110
111 switch (state->component) {
112 case CB_FMAP_VBLOCK_A:
113 fw_body_area = &state->cb_area[CB_FMAP_FW_MAIN_A];
Bill Richardson08efd1e2014-09-04 22:53:41 -0700114 /* Preserve the flags if they're not specified */
Bill Richardsona19b00d2014-09-04 23:20:43 -0700115 if (!option.flags_specified)
Bill Richardson08efd1e2014-09-04 22:53:41 -0700116 option.flags = preamble->flags;
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700117 break;
118 case CB_FMAP_VBLOCK_B:
119 fw_body_area = &state->cb_area[CB_FMAP_FW_MAIN_B];
120 break;
121 default:
122 DIE;
123 }
124
125 if (fw_size > fw_body_area->len) {
126 fprintf(stderr,
127 "%s says the firmware is larger than we have\n",
128 state->name);
129 return 1;
130 }
131
132 /* Update the firmware size */
133 fw_body_area->len = fw_size;
134
Bill Richardsone0519752014-09-03 14:20:10 -0700135whatever:
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700136 state->my_area->_flags |= AREA_IS_VALID;
137
138 return 0;
139}
140
141int futil_cb_sign_begin(struct futil_traverse_state_s *state)
142{
143 if (state->in_type == FILE_TYPE_UNKNOWN) {
144 fprintf(stderr, "Unable to determine type of %s\n",
145 state->in_filename);
146 return 1;
147 }
148
149 return 0;
150}
151
152static int write_new_preamble(struct cb_area_s *vblock,
153 struct cb_area_s *fw_body,
154 VbPrivateKey *signkey,
155 VbKeyBlockHeader *keyblock)
156{
157 VbSignature *body_sig;
158 VbFirmwarePreambleHeader *preamble;
159
160 body_sig = CalculateSignature(fw_body->buf, fw_body->len, signkey);
161 if (!body_sig) {
162 fprintf(stderr, "Error calculating body signature\n");
163 return 1;
164 }
165
166 preamble = CreateFirmwarePreamble(option.version,
167 option.kernel_subkey,
168 body_sig,
169 signkey,
170 option.flags);
171 if (!preamble) {
172 fprintf(stderr, "Error creating firmware preamble.\n");
173 free(body_sig);
174 return 1;
175 }
176
177 /* Write the new keyblock */
178 uint32_t more = keyblock->key_block_size;
179 memcpy(vblock->buf, keyblock, more);
180 /* and the new preamble */
181 memcpy(vblock->buf + more, preamble, preamble->preamble_size);
182
183 free(preamble);
184 free(body_sig);
185
186 return 0;
187}
188
189static int write_loem(const char *ab, struct cb_area_s *vblock)
190{
191 char filename[PATH_MAX];
192 int n;
193 n = snprintf(filename, sizeof(filename), "%s/vblock_%s.%s",
194 option.loemdir ? option.loemdir : ".",
195 ab, option.loemid);
196 if (n >= sizeof(filename)) {
197 fprintf(stderr, "LOEM args produce bogus filename\n");
198 return 1;
199 }
200
201 FILE *fp = fopen(filename, "w");
202 if (!fp) {
203 fprintf(stderr, "Can't open %s for writing: %s\n",
204 filename, strerror(errno));
205 return 1;
206 }
207
208 if (1 != fwrite(vblock->buf, vblock->len, 1, fp)) {
209 fprintf(stderr, "Can't write to %s: %s\n",
210 filename, strerror(errno));
211 fclose(fp);
212 return 1;
213 }
214 if (fclose(fp)) {
215 fprintf(stderr, "Failed closing loem output: %s\n",
216 strerror(errno));
217 return 1;
218 }
219
220 return 0;
221}
222
223int futil_cb_sign_end(struct futil_traverse_state_s *state)
224{
225 struct cb_area_s *vblock_a = &state->cb_area[CB_FMAP_VBLOCK_A];
226 struct cb_area_s *vblock_b = &state->cb_area[CB_FMAP_VBLOCK_B];
227 struct cb_area_s *fw_a = &state->cb_area[CB_FMAP_FW_MAIN_A];
228 struct cb_area_s *fw_b = &state->cb_area[CB_FMAP_FW_MAIN_B];
229 int retval = 0;
230
231 if (state->errors ||
232 !(vblock_a->_flags & AREA_IS_VALID) ||
233 !(vblock_b->_flags & AREA_IS_VALID) ||
234 !(fw_a->_flags & AREA_IS_VALID) ||
235 !(fw_b->_flags & AREA_IS_VALID)) {
236 fprintf(stderr, "Something's wrong. Not changing anything\n");
237 return 1;
238 }
239
240 /* Do A & B differ ? */
241 if (fw_a->len != fw_b->len ||
242 memcmp(fw_a->buf, fw_b->buf, fw_a->len)) {
243 /* Yes, must use DEV keys for A */
244 if (!option.devsignprivate || !option.devkeyblock) {
245 fprintf(stderr,
246 "FW A & B differ. DEV keys are required.\n");
247 return 1;
248 }
249 retval |= write_new_preamble(vblock_a, fw_a,
250 option.devsignprivate,
251 option.devkeyblock);
252 } else {
253 retval |= write_new_preamble(vblock_a, fw_a,
254 option.signprivate,
255 option.keyblock);
256 }
257
258 /* FW B is always normal keys */
259 retval |= write_new_preamble(vblock_b, fw_b,
260 option.signprivate,
261 option.keyblock);
262
263
264
265
266 if (option.loemid) {
267 retval |= write_loem("A", vblock_a);
268 retval |= write_loem("B", vblock_b);
269 }
270
271 return retval;
272}
273
274static const char usage[] = "\n"
275 "Usage: " MYNAME " %s [OPTIONS] FILE [OUTFILE]\n"
276 "\n"
277 "[Re]Sign the specified BIOS image\n"
278 "\n"
279 "Required OPTIONS:\n"
280 " -s|--signprivate FILE.vbprivk The private firmware data key\n"
281 " -b|--keyblock FILE.keyblock The keyblock containing the\n"
282 " public firmware data key\n"
283 " -k|--kernelkey FILE.vbpubk The public kernel subkey\n"
284 "\n"
285 "These are required if the A and B firmware differ:\n"
286 " -S|--devsign FILE.vbprivk The DEV private firmware data key\n"
287 " -B|--devkeyblock FILE.keyblock The keyblock containing the\n"
288 " DEV public firmware data key\n"
289 "\n"
290 "Optional OPTIONS:\n"
Bill Richardson08efd1e2014-09-04 22:53:41 -0700291 " -v|--version NUM The firmware version number"
292 " (default %d)\n"
293 " -f|--flags NUM The preamble flags value"
294 " (default is\n"
295 " unchanged, or 0 if unknown)\n"
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700296 " -d|--loemdir DIR Local OEM output vblock directory\n"
297 " -l|--loemid STRING Local OEM vblock suffix\n"
298 "\n";
299
300static void help_and_quit(const char *prog)
301{
Bill Richardson08efd1e2014-09-04 22:53:41 -0700302 fprintf(stderr, usage, prog, option.version);
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700303 exit(1);
304}
305
306static const struct option long_opts[] = {
307 /* name hasarg *flag val */
308 {"signprivate", 1, NULL, 's'},
309 {"keyblock", 1, NULL, 'b'},
310 {"kernelkey", 1, NULL, 'k'},
311 {"devsign", 1, NULL, 'S'},
312 {"devkeyblock", 1, NULL, 'B'},
313 {"version", 1, NULL, 'v'},
314 {"flags", 1, NULL, 'f'},
315 {"loemdir", 1, NULL, 'd'},
316 {"loemid", 1, NULL, 'l'},
317 {NULL, 0, NULL, 0},
318};
319static char *short_opts = ":s:b:k:S:B:v:f:d:l:";
320
321static int do_sign(int argc, char *argv[])
322{
323 char *infile = 0;
324 char *outfile = 0;
325 int fd, i;
326 int errorcnt = 0;
327 struct futil_traverse_state_s state;
328 char *e = 0;
329
330 opterr = 0; /* quiet, you */
331 while ((i = getopt_long(argc, argv, short_opts, long_opts, 0)) != -1) {
332 switch (i) {
333 case 's':
334 option.signprivate = PrivateKeyRead(optarg);
335 if (!option.signprivate) {
336 fprintf(stderr, "Error reading %s\n", optarg);
337 errorcnt++;
338 }
339 break;
340 case 'b':
341 option.keyblock = KeyBlockRead(optarg);
342 if (!option.keyblock) {
343 fprintf(stderr, "Error reading %s\n", optarg);
344 errorcnt++;
345 }
346 break;
347 case 'k':
348 option.kernel_subkey = PublicKeyRead(optarg);
349 if (!option.kernel_subkey) {
350 fprintf(stderr, "Error reading %s\n", optarg);
351 errorcnt++;
352 }
353 break;
354 case 'S':
355 option.devsignprivate = PrivateKeyRead(optarg);
356 if (!option.devsignprivate) {
357 fprintf(stderr, "Error reading %s\n", optarg);
358 errorcnt++;
359 }
360 break;
361 case 'B':
362 option.devkeyblock = KeyBlockRead(optarg);
363 if (!option.devkeyblock) {
364 fprintf(stderr, "Error reading %s\n", optarg);
365 errorcnt++;
366 }
367 break;
368 case 'v':
369 option.version = strtoul(optarg, &e, 0);
370 if (!*optarg || (e && *e)) {
371 fprintf(stderr,
372 "Invalid --version \"%s\"\n", optarg);
373 errorcnt++;
374 }
375 break;
376
377 case 'f':
Bill Richardsona19b00d2014-09-04 23:20:43 -0700378 option.flags_specified = 1;
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700379 option.flags = strtoul(optarg, &e, 0);
380 if (!*optarg || (e && *e)) {
381 fprintf(stderr,
382 "Invalid --flags \"%s\"\n", optarg);
383 errorcnt++;
384 }
Bill Richardsona19b00d2014-09-04 23:20:43 -0700385 break;
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700386 case 'd':
387 option.loemdir = optarg;
388 break;
389 case 'l':
390 option.loemid = optarg;
391 break;
392
393 case '?':
394 if (optopt)
395 fprintf(stderr, "Unrecognized option: -%c\n",
396 optopt);
397 else
398 fprintf(stderr, "Unrecognized option\n");
399 errorcnt++;
400 break;
401 case ':':
402 fprintf(stderr, "Missing argument to -%c\n", optopt);
403 errorcnt++;
404 break;
405 default:
406 DIE;
407 }
408 }
409
410 if (!option.signprivate) {
411 fprintf(stderr,
412 "Missing required private firmware data key\n");
413 errorcnt++;
414 }
415
416 if (!option.keyblock) {
417 fprintf(stderr,
418 "Missing required keyblock\n");
419 errorcnt++;
420 }
421
422 if (!option.kernel_subkey) {
423 fprintf(stderr,
424 "Missing required kernel subkey\n");
425 errorcnt++;
426 }
427
428 if (errorcnt)
429 help_and_quit(argv[0]);
430
431 switch (argc - optind) {
432 case 2:
433 infile = argv[optind++];
434 outfile = argv[optind++];
435 copy_file_or_die(infile, outfile);
436 break;
437 case 1:
438 /* Stomping right on it. Errors will leave it garbled. */
439 /* TODO: Use a tempfile (mkstemp) for normal files. */
440 infile = argv[optind++];
441 outfile = infile;
442 break;
443 case 0:
444 fprintf(stderr, "ERROR: missing input filename\n");
445 help_and_quit(argv[0]);
446 break;
447 default:
448 fprintf(stderr, "ERROR: too many arguments left over\n");
449 help_and_quit(argv[0]);
450 }
451
452
453 fd = open(outfile, O_RDWR);
454 if (fd < 0) {
455 fprintf(stderr, "Can't open %s: %s\n",
456 outfile, strerror(errno));
457 return 1;
458 }
459
460 memset(&state, 0, sizeof(state));
461 state.in_filename = outfile ? outfile : "<none>";
462 state.op = FUTIL_OP_SIGN;
463
464 errorcnt += futil_traverse(fd, &state, 1);
465
466 if (close(fd)) {
467 errorcnt++;
468 fprintf(stderr, "Error when closing %s: %s\n",
469 outfile, strerror(errno));
470 }
471
472 if (option.signprivate)
473 free(option.signprivate);
474 if (option.keyblock)
475 free(option.keyblock);
476 if (option.kernel_subkey)
477 free(option.kernel_subkey);
478
479 return !!errorcnt;
480}
481
482DECLARE_FUTIL_COMMAND(sign, do_sign, "[Re]Sign a BIOS image");