blob: 3a65b22eb6720c3a92c98f2d3119582d17a42749 [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 Richardson15dc6fc2014-09-02 14:45:44 -070085
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];
114 break;
115 case CB_FMAP_VBLOCK_B:
116 fw_body_area = &state->cb_area[CB_FMAP_FW_MAIN_B];
117 break;
118 default:
119 DIE;
120 }
121
122 if (fw_size > fw_body_area->len) {
123 fprintf(stderr,
124 "%s says the firmware is larger than we have\n",
125 state->name);
126 return 1;
127 }
128
129 /* Update the firmware size */
Bill Richardsone0519752014-09-03 14:20:10 -0700130 fprintf(stderr, "HEY: set FW size from %d to %d\n",
131 fw_body_area->len, fw_size);
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700132 fw_body_area->len = fw_size;
133
Bill Richardsone0519752014-09-03 14:20:10 -0700134whatever:
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700135 state->my_area->_flags |= AREA_IS_VALID;
136
137 return 0;
138}
139
140int futil_cb_sign_begin(struct futil_traverse_state_s *state)
141{
142 if (state->in_type == FILE_TYPE_UNKNOWN) {
143 fprintf(stderr, "Unable to determine type of %s\n",
144 state->in_filename);
145 return 1;
146 }
147
148 return 0;
149}
150
151static int write_new_preamble(struct cb_area_s *vblock,
152 struct cb_area_s *fw_body,
153 VbPrivateKey *signkey,
154 VbKeyBlockHeader *keyblock)
155{
156 VbSignature *body_sig;
157 VbFirmwarePreambleHeader *preamble;
158
159 body_sig = CalculateSignature(fw_body->buf, fw_body->len, signkey);
160 if (!body_sig) {
161 fprintf(stderr, "Error calculating body signature\n");
162 return 1;
163 }
164
165 preamble = CreateFirmwarePreamble(option.version,
166 option.kernel_subkey,
167 body_sig,
168 signkey,
169 option.flags);
170 if (!preamble) {
171 fprintf(stderr, "Error creating firmware preamble.\n");
172 free(body_sig);
173 return 1;
174 }
175
176 /* Write the new keyblock */
177 uint32_t more = keyblock->key_block_size;
178 memcpy(vblock->buf, keyblock, more);
179 /* and the new preamble */
180 memcpy(vblock->buf + more, preamble, preamble->preamble_size);
181
182 free(preamble);
183 free(body_sig);
184
185 return 0;
186}
187
188static int write_loem(const char *ab, struct cb_area_s *vblock)
189{
190 char filename[PATH_MAX];
191 int n;
192 n = snprintf(filename, sizeof(filename), "%s/vblock_%s.%s",
193 option.loemdir ? option.loemdir : ".",
194 ab, option.loemid);
195 if (n >= sizeof(filename)) {
196 fprintf(stderr, "LOEM args produce bogus filename\n");
197 return 1;
198 }
199
200 FILE *fp = fopen(filename, "w");
201 if (!fp) {
202 fprintf(stderr, "Can't open %s for writing: %s\n",
203 filename, strerror(errno));
204 return 1;
205 }
206
207 if (1 != fwrite(vblock->buf, vblock->len, 1, fp)) {
208 fprintf(stderr, "Can't write to %s: %s\n",
209 filename, strerror(errno));
210 fclose(fp);
211 return 1;
212 }
213 if (fclose(fp)) {
214 fprintf(stderr, "Failed closing loem output: %s\n",
215 strerror(errno));
216 return 1;
217 }
218
219 return 0;
220}
221
222int futil_cb_sign_end(struct futil_traverse_state_s *state)
223{
224 struct cb_area_s *vblock_a = &state->cb_area[CB_FMAP_VBLOCK_A];
225 struct cb_area_s *vblock_b = &state->cb_area[CB_FMAP_VBLOCK_B];
226 struct cb_area_s *fw_a = &state->cb_area[CB_FMAP_FW_MAIN_A];
227 struct cb_area_s *fw_b = &state->cb_area[CB_FMAP_FW_MAIN_B];
228 int retval = 0;
229
230 if (state->errors ||
231 !(vblock_a->_flags & AREA_IS_VALID) ||
232 !(vblock_b->_flags & AREA_IS_VALID) ||
233 !(fw_a->_flags & AREA_IS_VALID) ||
234 !(fw_b->_flags & AREA_IS_VALID)) {
235 fprintf(stderr, "Something's wrong. Not changing anything\n");
236 return 1;
237 }
238
239 /* Do A & B differ ? */
240 if (fw_a->len != fw_b->len ||
241 memcmp(fw_a->buf, fw_b->buf, fw_a->len)) {
242 /* Yes, must use DEV keys for A */
243 if (!option.devsignprivate || !option.devkeyblock) {
244 fprintf(stderr,
245 "FW A & B differ. DEV keys are required.\n");
246 return 1;
247 }
248 retval |= write_new_preamble(vblock_a, fw_a,
249 option.devsignprivate,
250 option.devkeyblock);
251 } else {
252 retval |= write_new_preamble(vblock_a, fw_a,
253 option.signprivate,
254 option.keyblock);
255 }
256
257 /* FW B is always normal keys */
258 retval |= write_new_preamble(vblock_b, fw_b,
259 option.signprivate,
260 option.keyblock);
261
262
263
264
265 if (option.loemid) {
266 retval |= write_loem("A", vblock_a);
267 retval |= write_loem("B", vblock_b);
268 }
269
270 return retval;
271}
272
273static const char usage[] = "\n"
274 "Usage: " MYNAME " %s [OPTIONS] FILE [OUTFILE]\n"
275 "\n"
276 "[Re]Sign the specified BIOS image\n"
277 "\n"
278 "Required OPTIONS:\n"
279 " -s|--signprivate FILE.vbprivk The private firmware data key\n"
280 " -b|--keyblock FILE.keyblock The keyblock containing the\n"
281 " public firmware data key\n"
282 " -k|--kernelkey FILE.vbpubk The public kernel subkey\n"
283 "\n"
284 "These are required if the A and B firmware differ:\n"
285 " -S|--devsign FILE.vbprivk The DEV private firmware data key\n"
286 " -B|--devkeyblock FILE.keyblock The keyblock containing the\n"
287 " DEV public firmware data key\n"
288 "\n"
289 "Optional OPTIONS:\n"
290 " -v|--version NUM The firmware version number (%d)\n"
291 " -f|--flags NUM The preamble flags value (%d)\n"
292 " -d|--loemdir DIR Local OEM output vblock directory\n"
293 " -l|--loemid STRING Local OEM vblock suffix\n"
294 "\n";
295
296static void help_and_quit(const char *prog)
297{
298 fprintf(stderr, usage, prog, option.version, option.flags);
299 exit(1);
300}
301
302static const struct option long_opts[] = {
303 /* name hasarg *flag val */
304 {"signprivate", 1, NULL, 's'},
305 {"keyblock", 1, NULL, 'b'},
306 {"kernelkey", 1, NULL, 'k'},
307 {"devsign", 1, NULL, 'S'},
308 {"devkeyblock", 1, NULL, 'B'},
309 {"version", 1, NULL, 'v'},
310 {"flags", 1, NULL, 'f'},
311 {"loemdir", 1, NULL, 'd'},
312 {"loemid", 1, NULL, 'l'},
313 {NULL, 0, NULL, 0},
314};
315static char *short_opts = ":s:b:k:S:B:v:f:d:l:";
316
317static int do_sign(int argc, char *argv[])
318{
319 char *infile = 0;
320 char *outfile = 0;
321 int fd, i;
322 int errorcnt = 0;
323 struct futil_traverse_state_s state;
324 char *e = 0;
325
326 opterr = 0; /* quiet, you */
327 while ((i = getopt_long(argc, argv, short_opts, long_opts, 0)) != -1) {
328 switch (i) {
329 case 's':
330 option.signprivate = PrivateKeyRead(optarg);
331 if (!option.signprivate) {
332 fprintf(stderr, "Error reading %s\n", optarg);
333 errorcnt++;
334 }
335 break;
336 case 'b':
337 option.keyblock = KeyBlockRead(optarg);
338 if (!option.keyblock) {
339 fprintf(stderr, "Error reading %s\n", optarg);
340 errorcnt++;
341 }
342 break;
343 case 'k':
344 option.kernel_subkey = PublicKeyRead(optarg);
345 if (!option.kernel_subkey) {
346 fprintf(stderr, "Error reading %s\n", optarg);
347 errorcnt++;
348 }
349 break;
350 case 'S':
351 option.devsignprivate = PrivateKeyRead(optarg);
352 if (!option.devsignprivate) {
353 fprintf(stderr, "Error reading %s\n", optarg);
354 errorcnt++;
355 }
356 break;
357 case 'B':
358 option.devkeyblock = KeyBlockRead(optarg);
359 if (!option.devkeyblock) {
360 fprintf(stderr, "Error reading %s\n", optarg);
361 errorcnt++;
362 }
363 break;
364 case 'v':
365 option.version = strtoul(optarg, &e, 0);
366 if (!*optarg || (e && *e)) {
367 fprintf(stderr,
368 "Invalid --version \"%s\"\n", optarg);
369 errorcnt++;
370 }
371 break;
372
373 case 'f':
374 option.flags = strtoul(optarg, &e, 0);
375 if (!*optarg || (e && *e)) {
376 fprintf(stderr,
377 "Invalid --flags \"%s\"\n", optarg);
378 errorcnt++;
379 }
380 case 'd':
381 option.loemdir = optarg;
382 break;
383 case 'l':
384 option.loemid = optarg;
385 break;
386
387 case '?':
388 if (optopt)
389 fprintf(stderr, "Unrecognized option: -%c\n",
390 optopt);
391 else
392 fprintf(stderr, "Unrecognized option\n");
393 errorcnt++;
394 break;
395 case ':':
396 fprintf(stderr, "Missing argument to -%c\n", optopt);
397 errorcnt++;
398 break;
399 default:
400 DIE;
401 }
402 }
403
404 if (!option.signprivate) {
405 fprintf(stderr,
406 "Missing required private firmware data key\n");
407 errorcnt++;
408 }
409
410 if (!option.keyblock) {
411 fprintf(stderr,
412 "Missing required keyblock\n");
413 errorcnt++;
414 }
415
416 if (!option.kernel_subkey) {
417 fprintf(stderr,
418 "Missing required kernel subkey\n");
419 errorcnt++;
420 }
421
422 if (errorcnt)
423 help_and_quit(argv[0]);
424
425 switch (argc - optind) {
426 case 2:
427 infile = argv[optind++];
428 outfile = argv[optind++];
429 copy_file_or_die(infile, outfile);
430 break;
431 case 1:
432 /* Stomping right on it. Errors will leave it garbled. */
433 /* TODO: Use a tempfile (mkstemp) for normal files. */
434 infile = argv[optind++];
435 outfile = infile;
436 break;
437 case 0:
438 fprintf(stderr, "ERROR: missing input filename\n");
439 help_and_quit(argv[0]);
440 break;
441 default:
442 fprintf(stderr, "ERROR: too many arguments left over\n");
443 help_and_quit(argv[0]);
444 }
445
446
447 fd = open(outfile, O_RDWR);
448 if (fd < 0) {
449 fprintf(stderr, "Can't open %s: %s\n",
450 outfile, strerror(errno));
451 return 1;
452 }
453
454 memset(&state, 0, sizeof(state));
455 state.in_filename = outfile ? outfile : "<none>";
456 state.op = FUTIL_OP_SIGN;
457
458 errorcnt += futil_traverse(fd, &state, 1);
459
460 if (close(fd)) {
461 errorcnt++;
462 fprintf(stderr, "Error when closing %s: %s\n",
463 outfile, strerror(errno));
464 }
465
466 if (option.signprivate)
467 free(option.signprivate);
468 if (option.keyblock)
469 free(option.keyblock);
470 if (option.kernel_subkey)
471 free(option.kernel_subkey);
472
473 return !!errorcnt;
474}
475
476DECLARE_FUTIL_COMMAND(sign, do_sign, "[Re]Sign a BIOS image");