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