blob: c28aee99821eb783936e6f96fc0c9ce9c8131e08 [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"
Bill Richardson5f2696d2014-09-23 22:03:56 -070025#include "kernel_blob.h"
Bill Richardson15dc6fc2014-09-02 14:45:44 -070026#include "traversal.h"
27#include "util_misc.h"
Bill Richardson5f2696d2014-09-23 22:03:56 -070028#include "vb1_helper.h"
Bill Richardson15dc6fc2014-09-02 14:45:44 -070029#include "vboot_common.h"
30
31/* Local values for cb_area_s._flags */
32enum callback_flags {
33 AREA_IS_VALID = 0x00000001,
34};
35
36/* Local structure for args, etc. */
Bill Richardson5f2696d2014-09-23 22:03:56 -070037static struct local_data_s {
Bill Richardson15dc6fc2014-09-02 14:45:44 -070038 VbPrivateKey *signprivate;
39 VbKeyBlockHeader *keyblock;
40 VbPublicKey *kernel_subkey;
41 VbPrivateKey *devsignprivate;
42 VbKeyBlockHeader *devkeyblock;
43 uint32_t version;
Bill Richardson5f2696d2014-09-23 22:03:56 -070044 int version_specified;
Bill Richardson15dc6fc2014-09-02 14:45:44 -070045 uint32_t flags;
Bill Richardsona19b00d2014-09-04 23:20:43 -070046 int flags_specified;
Bill Richardson15dc6fc2014-09-02 14:45:44 -070047 char *loemdir;
48 char *loemid;
Bill Richardson5f2696d2014-09-23 22:03:56 -070049 uint8_t *bootloader_data;
50 uint64_t bootloader_size;
51 uint8_t *config_data;
52 uint64_t config_size;
53 enum arch_t arch;
Bill Richardsonc540f592014-09-23 22:17:02 -070054 int fv_specified;
Bill Richardson5f2696d2014-09-23 22:03:56 -070055 uint32_t kloadaddr;
56 uint32_t padding;
57 int vblockonly;
58 char *outfile;
59 int create_new_outfile;
Bill Richardsonc540f592014-09-23 22:17:02 -070060 char *pem_signpriv;
61 int pem_algo_specified;
62 uint32_t pem_algo;
63 char *pem_external;
Bill Richardson15dc6fc2014-09-02 14:45:44 -070064} option = {
65 .version = 1,
Bill Richardson5f2696d2014-09-23 22:03:56 -070066 .arch = ARCH_UNSPECIFIED,
67 .kloadaddr = CROS_32BIT_ENTRY_ADDR,
68 .padding = 65536,
Bill Richardson15dc6fc2014-09-02 14:45:44 -070069};
70
71
Bill Richardson5f2696d2014-09-23 22:03:56 -070072/* Helper to complain about invalid args. Returns num errors discovered */
73static int no_opt_if(int expr, const char *optname)
Bill Richardson15dc6fc2014-09-02 14:45:44 -070074{
Bill Richardson5f2696d2014-09-23 22:03:56 -070075 if (expr) {
76 fprintf(stderr, "Missing --%s option\n", optname);
77 return 1;
78 }
79 return 0;
Bill Richardson15dc6fc2014-09-02 14:45:44 -070080}
81
Bill Richardson5f2696d2014-09-23 22:03:56 -070082/* This wraps/signs a public key, producing a keyblock. */
83int futil_cb_sign_pubkey(struct futil_traverse_state_s *state)
Bill Richardson15dc6fc2014-09-02 14:45:44 -070084{
Bill Richardsonc540f592014-09-23 22:17:02 -070085 VbPublicKey *data_key = (VbPublicKey *)state->my_area->buf;
86 VbKeyBlockHeader *vblock;
87
88 if (option.pem_signpriv) {
89 if (option.pem_external) {
90 /* External signing uses the PEM file directly. */
91 vblock = KeyBlockCreate_external(
92 data_key,
93 option.pem_signpriv,
94 option.pem_algo, option.flags,
95 option.pem_external);
96 } else {
97 option.signprivate = PrivateKeyReadPem(
98 option.pem_signpriv, option.pem_algo);
99 if (!option.signprivate) {
100 fprintf(stderr,
101 "Unable to read PEM signing key: %s\n",
102 strerror(errno));
103 return 1;
104 }
105 vblock = KeyBlockCreate(data_key, option.signprivate,
106 option.flags);
107 }
108 } else {
109 /* Not PEM. Should already have a signing key. */
110 vblock = KeyBlockCreate(data_key, option.signprivate,
111 option.flags);
112 }
113
114 /* Write it out */
115 return WriteSomeParts(option.outfile,
116 vblock, vblock->key_block_size,
117 NULL, 0);
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700118}
119
120/*
121 * This handles FW_MAIN_A and FW_MAIN_B while processing a BIOS image.
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700122 * The data in state->my_area is just the RW firmware blob, so there's nothing
123 * useful to show about it. We'll just mark it as present so when we encounter
124 * corresponding VBLOCK area, we'll have this to verify.
125 */
126int futil_cb_sign_fw_main(struct futil_traverse_state_s *state)
127{
128 state->my_area->_flags |= AREA_IS_VALID;
129 return 0;
130}
131
Bill Richardson779796f2014-09-23 11:47:40 -0700132/*
133 * This handles VBLOCK_A and VBLOCK_B while processing a BIOS image.
134 * We don't do any signing here. We just check to see if the VBLOCK
135 * area contains a firmware preamble.
136 */
Bill Richardson5f2696d2014-09-23 22:03:56 -0700137int futil_cb_sign_fw_vblock(struct futil_traverse_state_s *state)
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700138{
139 VbKeyBlockHeader *key_block = (VbKeyBlockHeader *)state->my_area->buf;
Bill Richardsone0519752014-09-03 14:20:10 -0700140 uint32_t len = state->my_area->len;
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700141
Bill Richardsone0519752014-09-03 14:20:10 -0700142 /*
143 * If we have a valid keyblock and fw_preamble, then we can use them to
144 * determine the size of the firmware body. Otherwise, we'll have to
145 * just sign the whole region.
146 */
147 if (VBOOT_SUCCESS != KeyBlockVerify(key_block, len, NULL, 1)) {
148 fprintf(stderr, "Warning: %s keyblock is invalid. "
149 "Signing the entire FW FMAP region...\n",
Bill Richardson779796f2014-09-23 11:47:40 -0700150 state->name);
Bill Richardsone0519752014-09-03 14:20:10 -0700151 goto whatever;
152 }
153
154 RSAPublicKey *rsa = PublicKeyToRSA(&key_block->data_key);
155 if (!rsa) {
156 fprintf(stderr, "Warning: %s public key is invalid. "
157 "Signing the entire FW FMAP region...\n",
158 state->name);
159 goto whatever;
160 }
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700161 uint32_t more = key_block->key_block_size;
162 VbFirmwarePreambleHeader *preamble =
163 (VbFirmwarePreambleHeader *)(state->my_area->buf + more);
164 uint32_t fw_size = preamble->body_signature.data_size;
Bill Richardsone0519752014-09-03 14:20:10 -0700165 struct cb_area_s *fw_body_area = 0;
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700166
167 switch (state->component) {
168 case CB_FMAP_VBLOCK_A:
169 fw_body_area = &state->cb_area[CB_FMAP_FW_MAIN_A];
Bill Richardson08efd1e2014-09-04 22:53:41 -0700170 /* Preserve the flags if they're not specified */
Bill Richardsona19b00d2014-09-04 23:20:43 -0700171 if (!option.flags_specified)
Bill Richardson08efd1e2014-09-04 22:53:41 -0700172 option.flags = preamble->flags;
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700173 break;
174 case CB_FMAP_VBLOCK_B:
175 fw_body_area = &state->cb_area[CB_FMAP_FW_MAIN_B];
176 break;
177 default:
178 DIE;
179 }
180
181 if (fw_size > fw_body_area->len) {
182 fprintf(stderr,
183 "%s says the firmware is larger than we have\n",
Bill Richardson779796f2014-09-23 11:47:40 -0700184 state->name);
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700185 return 1;
186 }
187
188 /* Update the firmware size */
189 fw_body_area->len = fw_size;
190
Bill Richardsone0519752014-09-03 14:20:10 -0700191whatever:
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700192 state->my_area->_flags |= AREA_IS_VALID;
193
194 return 0;
195}
196
Bill Richardson5f2696d2014-09-23 22:03:56 -0700197int futil_cb_create_kernel_part(struct futil_traverse_state_s *state)
198{
199 uint8_t *vmlinuz_data, *kblob_data, *vblock_data;
200 uint64_t vmlinuz_size, kblob_size, vblock_size;
201 int rv;
202
203 vmlinuz_data = state->my_area->buf;
204 vmlinuz_size = state->my_area->len;
205
206 kblob_data = CreateKernelBlob(
207 vmlinuz_data, vmlinuz_size,
208 option.arch, option.kloadaddr,
209 option.config_data, option.config_size,
210 option.bootloader_data, option.bootloader_size,
211 &kblob_size);
212 if (!kblob_data) {
213 fprintf(stderr, "Unable to create kernel blob\n");
214 return 1;
215 }
216 Debug("kblob_size = 0x%" PRIx64 "\n", kblob_size);
217
218 vblock_data = SignKernelBlob(kblob_data, kblob_size, option.padding,
219 option.version, option.kloadaddr,
220 option.keyblock, option.signprivate,
221 &vblock_size);
222 if (!vblock_data) {
223 fprintf(stderr, "Unable to sign kernel blob\n");
224 free(kblob_data);
225 return 1;
226 }
227 Debug("vblock_size = 0x%" PRIx64 "\n", vblock_size);
228
229 /* We should be creating a completely new output file.
230 * If not, something's wrong. */
231 if (!option.create_new_outfile)
232 DIE;
233
234 if (option.vblockonly)
235 rv = WriteSomeParts(option.outfile,
236 vblock_data, vblock_size,
237 NULL, 0);
238 else
239 rv = WriteSomeParts(option.outfile,
240 vblock_data, vblock_size,
241 kblob_data, kblob_size);
242
243 free(vblock_data);
244 free(kblob_data);
245 return rv;
246}
247
248int futil_cb_resign_kernel_part(struct futil_traverse_state_s *state)
249{
250 uint8_t *kpart_data, *kblob_data, *vblock_data;
251 uint64_t kpart_size, kblob_size, vblock_size;
252 VbKeyBlockHeader *keyblock = NULL;
253 VbKernelPreambleHeader *preamble = NULL;
254 int rv = 0;
255
256 kpart_data = state->my_area->buf;
257 kpart_size = state->my_area->len;
258
259 /* Note: This just sets some static pointers. It doesn't malloc. */
260 kblob_data = UnpackKPart(kpart_data, kpart_size, option.padding,
261 &keyblock, &preamble, &kblob_size);
262
263 if (!kblob_data) {
264 fprintf(stderr, "Unable to unpack kernel partition\n");
265 return 1;
266 }
267
268 /*
269 * We don't let --kloadaddr change when resigning, because the original
270 * vbutil_kernel program didn't do it right. Since obviously no one
271 * ever noticed, we'll maintain bug-compatibility by just not allowing
272 * it here either. To enable it, we'd need to update the zeropage
273 * table's cmd_line_ptr as well as the preamble.
274 */
275 option.kloadaddr = preamble->body_load_address;
276
277 /* Replace the config if asked */
278 if (option.config_data &&
279 0 != UpdateKernelBlobConfig(kblob_data, kblob_size,
280 option.config_data,
281 option.config_size)) {
282 fprintf(stderr, "Unable to update config\n");
283 return 1;
284 }
285
286 /* Preserve the version unless a new one is given */
287 if (!option.version_specified)
288 option.version = preamble->kernel_version;
289
290 /* Replace the keyblock if asked */
291 if (option.keyblock)
292 keyblock = option.keyblock;
293
294 /* Compute the new signature */
295 vblock_data = SignKernelBlob(kblob_data, kblob_size, option.padding,
296 option.version, option.kloadaddr,
297 keyblock, option.signprivate,
298 &vblock_size);
299 if (!vblock_data) {
300 fprintf(stderr, "Unable to sign kernel blob\n");
301 return 1;
302 }
303 Debug("vblock_size = 0x%" PRIx64 "\n", vblock_size);
304
305 if (option.vblockonly) {
306 /* If we're only writing the vblock, then we should be doing it
307 * into a new file. */
308 rv = WriteSomeParts(option.outfile,
309 vblock_data, vblock_size,
310 NULL, 0);
311 } else {
312 /* If we're writing the whole thing, then the output is
313 * the same size (and possibly the same file) as the input.
314 * Either way, it's mmap'ed so modifications to the buffer
315 * will get flushed to disk when we close the file. */
316 Memcpy(kpart_data, vblock_data, vblock_size);
317 }
318
319 free(vblock_data);
320 return rv;
321}
322
323
324int futil_cb_sign_raw_firmware(struct futil_traverse_state_s *state)
325{
Bill Richardsonc540f592014-09-23 22:17:02 -0700326 VbSignature *body_sig;
327 VbFirmwarePreambleHeader *preamble;
328 int rv;
329
330 body_sig = CalculateSignature(state->my_area->buf, state->my_area->len,
331 option.signprivate);
332 if (!body_sig) {
333 fprintf(stderr, "Error calculating body signature\n");
334 return 1;
335 }
336
337 preamble = CreateFirmwarePreamble(option.version,
338 option.kernel_subkey,
339 body_sig,
340 option.signprivate,
341 option.flags);
342 if (!preamble) {
343 fprintf(stderr, "Error creating firmware preamble.\n");
344 free(body_sig);
345 return 1;
346 }
347
348 rv = WriteSomeParts(option.outfile,
349 option.keyblock, option.keyblock->key_block_size,
350 preamble, preamble->preamble_size);
351
352 free(preamble);
353 free(body_sig);
354
355 return rv;
Bill Richardson5f2696d2014-09-23 22:03:56 -0700356}
357
358
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700359int futil_cb_sign_begin(struct futil_traverse_state_s *state)
360{
361 if (state->in_type == FILE_TYPE_UNKNOWN) {
362 fprintf(stderr, "Unable to determine type of %s\n",
363 state->in_filename);
364 return 1;
365 }
366
367 return 0;
368}
369
370static int write_new_preamble(struct cb_area_s *vblock,
371 struct cb_area_s *fw_body,
372 VbPrivateKey *signkey,
373 VbKeyBlockHeader *keyblock)
374{
375 VbSignature *body_sig;
376 VbFirmwarePreambleHeader *preamble;
377
378 body_sig = CalculateSignature(fw_body->buf, fw_body->len, signkey);
379 if (!body_sig) {
380 fprintf(stderr, "Error calculating body signature\n");
381 return 1;
382 }
383
384 preamble = CreateFirmwarePreamble(option.version,
385 option.kernel_subkey,
386 body_sig,
387 signkey,
388 option.flags);
389 if (!preamble) {
390 fprintf(stderr, "Error creating firmware preamble.\n");
391 free(body_sig);
392 return 1;
393 }
394
395 /* Write the new keyblock */
396 uint32_t more = keyblock->key_block_size;
397 memcpy(vblock->buf, keyblock, more);
398 /* and the new preamble */
399 memcpy(vblock->buf + more, preamble, preamble->preamble_size);
400
401 free(preamble);
402 free(body_sig);
403
404 return 0;
405}
406
407static int write_loem(const char *ab, struct cb_area_s *vblock)
408{
409 char filename[PATH_MAX];
410 int n;
411 n = snprintf(filename, sizeof(filename), "%s/vblock_%s.%s",
412 option.loemdir ? option.loemdir : ".",
413 ab, option.loemid);
414 if (n >= sizeof(filename)) {
415 fprintf(stderr, "LOEM args produce bogus filename\n");
416 return 1;
417 }
418
419 FILE *fp = fopen(filename, "w");
420 if (!fp) {
421 fprintf(stderr, "Can't open %s for writing: %s\n",
422 filename, strerror(errno));
423 return 1;
424 }
425
426 if (1 != fwrite(vblock->buf, vblock->len, 1, fp)) {
427 fprintf(stderr, "Can't write to %s: %s\n",
428 filename, strerror(errno));
429 fclose(fp);
430 return 1;
431 }
432 if (fclose(fp)) {
433 fprintf(stderr, "Failed closing loem output: %s\n",
434 strerror(errno));
435 return 1;
436 }
437
438 return 0;
439}
440
Bill Richardson5f2696d2014-09-23 22:03:56 -0700441/* This signs a full BIOS image after it's been traversed. */
442static int sign_bios_at_end(struct futil_traverse_state_s *state)
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700443{
444 struct cb_area_s *vblock_a = &state->cb_area[CB_FMAP_VBLOCK_A];
445 struct cb_area_s *vblock_b = &state->cb_area[CB_FMAP_VBLOCK_B];
446 struct cb_area_s *fw_a = &state->cb_area[CB_FMAP_FW_MAIN_A];
447 struct cb_area_s *fw_b = &state->cb_area[CB_FMAP_FW_MAIN_B];
448 int retval = 0;
449
450 if (state->errors ||
451 !(vblock_a->_flags & AREA_IS_VALID) ||
452 !(vblock_b->_flags & AREA_IS_VALID) ||
453 !(fw_a->_flags & AREA_IS_VALID) ||
454 !(fw_b->_flags & AREA_IS_VALID)) {
455 fprintf(stderr, "Something's wrong. Not changing anything\n");
456 return 1;
457 }
458
459 /* Do A & B differ ? */
460 if (fw_a->len != fw_b->len ||
461 memcmp(fw_a->buf, fw_b->buf, fw_a->len)) {
462 /* Yes, must use DEV keys for A */
463 if (!option.devsignprivate || !option.devkeyblock) {
464 fprintf(stderr,
465 "FW A & B differ. DEV keys are required.\n");
466 return 1;
467 }
468 retval |= write_new_preamble(vblock_a, fw_a,
469 option.devsignprivate,
470 option.devkeyblock);
471 } else {
472 retval |= write_new_preamble(vblock_a, fw_a,
473 option.signprivate,
474 option.keyblock);
475 }
476
477 /* FW B is always normal keys */
478 retval |= write_new_preamble(vblock_b, fw_b,
479 option.signprivate,
480 option.keyblock);
481
482
483
484
485 if (option.loemid) {
486 retval |= write_loem("A", vblock_a);
487 retval |= write_loem("B", vblock_b);
488 }
489
490 return retval;
491}
492
Bill Richardson5f2696d2014-09-23 22:03:56 -0700493int futil_cb_sign_end(struct futil_traverse_state_s *state)
494{
495 switch (state->in_type) {
496 case FILE_TYPE_BIOS_IMAGE:
497 case FILE_TYPE_OLD_BIOS_IMAGE:
498 return sign_bios_at_end(state);
499
500 default:
501 /* Any other cleanup needed? */
502 break;
503 }
504
505 return state->errors;
506}
507
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700508static const char usage[] = "\n"
Bill Richardson5f2696d2014-09-23 22:03:56 -0700509 "Usage: " MYNAME " %s [PARAMS] INFILE [OUTFILE]\n"
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700510 "\n"
Bill Richardson5f2696d2014-09-23 22:03:56 -0700511 "Where INFILE is a\n"
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700512 "\n"
Bill Richardsonc540f592014-09-23 22:17:02 -0700513 " public key (.vbpubk); OUTFILE is a keyblock\n"
514 " raw firmware blob (FW_MAIN_A/B); OUTFILE is a VBLOCK_A/B\n"
Bill Richardson5f2696d2014-09-23 22:03:56 -0700515 " complete firmware image (bios.bin)\n"
516 " raw linux kernel; OUTFILE is a kernel partition image\n"
517 " kernel partition image (/dev/sda2, /dev/mmcblk0p2)\n";
518
Bill Richardsonc540f592014-09-23 22:17:02 -0700519static const char usage_pubkey[] = "\n"
520 "-----------------------------------------------------------------\n"
521 "To sign a public key / create a new keyblock:\n"
522 "\n"
523 "Required PARAMS:\n"
524 " [--datapubkey] INFILE The public key to wrap\n"
525 " [--outfile] OUTFILE The resulting keyblock\n"
526 "\n"
527 "Optional PARAMS:\n"
528 " A private signing key, specified as either\n"
529 " -s|--signprivate FILE.vbprivk Signing key in .vbprivk format\n"
530 " Or\n"
531 " --pem_signpriv FILE.pem Signing key in PEM format...\n"
532 " --pem_algo NUM AND the algorithm to use (0 - %d)\n"
533 "\n"
534 " If a signing key is not given, the keyblock will not be signed (duh)."
535 "\n\n"
536 "And these, too:\n\n"
537 " -f|--flags NUM Flags specifying use conditions\n"
538 " --pem_external PROGRAM"
539 " External program to compute the signature\n"
540 " (requires a PEM signing key)\n";
541
542static const char usage_fw_main[] = "\n"
543 "-----------------------------------------------------------------\n"
544 "To sign a raw firmware blob (FW_MAIN_A/B):\n"
545 "\n"
546 "Required PARAMS:\n"
547 " -s|--signprivate FILE.vbprivk The private firmware data key\n"
548 " -b|--keyblock FILE.keyblock The keyblock containing the\n"
549 " public firmware data key\n"
550 " -k|--kernelkey FILE.vbpubk The public kernel subkey\n"
551 " -v|--version NUM The firmware version number\n"
552 " [--fv] INFILE"
553 " The raw firmware blob (FW_MAIN_A/B)\n"
554 " [--outfile] OUTFILE Output VBLOCK_A/B\n"
555 "\n"
556 "Optional PARAMS:\n"
557 " -f|--flags NUM The preamble flags value"
558 " (default is 0)\n";
559
Bill Richardson5f2696d2014-09-23 22:03:56 -0700560static const char usage_bios[] = "\n"
561 "-----------------------------------------------------------------\n"
562 "To sign a complete firmware image (bios.bin):\n"
563 "\n"
564 "Required PARAMS:\n"
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700565 " -s|--signprivate FILE.vbprivk The private firmware data key\n"
566 " -b|--keyblock FILE.keyblock The keyblock containing the\n"
567 " public firmware data key\n"
568 " -k|--kernelkey FILE.vbpubk The public kernel subkey\n"
Bill Richardson5f2696d2014-09-23 22:03:56 -0700569 " [--infile] INFILE Input firmware image (modified\n"
570 " in place if no OUTFILE given)\n"
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700571 "\n"
572 "These are required if the A and B firmware differ:\n"
573 " -S|--devsign FILE.vbprivk The DEV private firmware data key\n"
574 " -B|--devkeyblock FILE.keyblock The keyblock containing the\n"
575 " DEV public firmware data key\n"
576 "\n"
Bill Richardson5f2696d2014-09-23 22:03:56 -0700577 "Optional PARAMS:\n"
Bill Richardson08efd1e2014-09-04 22:53:41 -0700578 " -v|--version NUM The firmware version number"
579 " (default %d)\n"
580 " -f|--flags NUM The preamble flags value"
581 " (default is\n"
582 " unchanged, or 0 if unknown)\n"
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700583 " -d|--loemdir DIR Local OEM output vblock directory\n"
584 " -l|--loemid STRING Local OEM vblock suffix\n"
Bill Richardson5f2696d2014-09-23 22:03:56 -0700585 " [--outfile] OUTFILE Output firmware image\n";
586
587static const char usage_new_kpart[] = "\n"
588 "-----------------------------------------------------------------\n"
589 "To create a new kernel parition image (/dev/sda2, /dev/mmcblk0p2):\n"
590 "\n"
591 "Required PARAMS:\n"
592 " -s|--signprivate FILE.vbprivk"
593 " The private key to sign the kernel blob\n"
594 " -b|--keyblock FILE.keyblock The keyblock containing the public\n"
595 " key to verify the kernel blob\n"
596 " -v|--version NUM The kernel version number\n"
597 " --bootloader FILE Bootloader stub\n"
598 " --config FILE The kernel commandline file\n"
599 " --arch ARCH The CPU architecture (one of\n"
600 " x86|amd64, arm|aarch64, mips)\n"
601 " [--vmlinuz] INFILE Linux kernel bzImage file\n"
602 " [--outfile] OUTFILE Output kernel partition or vblock\n"
603 "\n"
604 "Optional PARAMS:\n"
605 " --kloadaddr NUM"
606 " RAM address to load the kernel body\n"
607 " (default 0x%x)\n"
608 " --pad NUM The vblock padding size in bytes\n"
609 " (default 0x%x)\n"
610 " --vblockonly Emit just the vblock (requires a\n"
611 " distinct outfile)\n";
612
613static const char usage_old_kpart[] = "\n"
614 "-----------------------------------------------------------------\n"
615 "To resign an existing kernel parition (/dev/sda2, /dev/mmcblk0p2):\n"
616 "\n"
617 "Required PARAMS:\n"
618 " -s|--signprivate FILE.vbprivk"
619 " The private key to sign the kernel blob\n"
620 " [--infile] INFILE Input kernel partition (modified\n"
621 " in place if no OUTFILE given)\n"
622 "\n"
623 "Optional PARAMS:\n"
624 " -b|--keyblock FILE.keyblock The keyblock containing the public\n"
625 " key to verify the kernel blob\n"
626 " -v|--version NUM The kernel version number\n"
627 " --config FILE The kernel commandline file\n"
628 " --pad NUM The vblock padding size in bytes\n"
629 " (default 0x%x)\n"
630 " [--outfile] OUTFILE Output kernel partition or vblock\n"
631 " --vblockonly Emit just the vblock (requires a\n"
632 " distinct OUTFILE)\n"
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700633 "\n";
634
Bill Richardson779796f2014-09-23 11:47:40 -0700635static void print_help(const char *prog)
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700636{
Bill Richardson5f2696d2014-09-23 22:03:56 -0700637 printf(usage, prog);
Bill Richardsonc540f592014-09-23 22:17:02 -0700638 printf(usage_pubkey, kNumAlgorithms - 1);
639 puts(usage_fw_main);
Bill Richardson5f2696d2014-09-23 22:03:56 -0700640 printf(usage_bios, option.version);
641 printf(usage_new_kpart, option.kloadaddr, option.padding);
642 printf(usage_old_kpart, option.padding);
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700643}
644
Bill Richardson5f2696d2014-09-23 22:03:56 -0700645enum no_short_opts {
646 OPT_FV = 1000,
647 OPT_INFILE, /* aka "--vmlinuz" */
648 OPT_OUTFILE,
649 OPT_BOOTLOADER,
650 OPT_CONFIG,
651 OPT_ARCH,
652 OPT_KLOADADDR,
653 OPT_PADDING,
Bill Richardsonc540f592014-09-23 22:17:02 -0700654 OPT_PEM_SIGNPRIV,
655 OPT_PEM_ALGO,
656 OPT_PEM_EXTERNAL,
Bill Richardson5f2696d2014-09-23 22:03:56 -0700657};
658
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700659static const struct option long_opts[] = {
660 /* name hasarg *flag val */
Bill Richardson5f2696d2014-09-23 22:03:56 -0700661 {"signprivate", 1, NULL, 's'},
662 {"keyblock", 1, NULL, 'b'},
663 {"kernelkey", 1, NULL, 'k'},
664 {"devsign", 1, NULL, 'S'},
665 {"devkeyblock", 1, NULL, 'B'},
666 {"version", 1, NULL, 'v'},
667 {"flags", 1, NULL, 'f'},
668 {"loemdir", 1, NULL, 'd'},
669 {"loemid", 1, NULL, 'l'},
670 {"fv", 1, NULL, OPT_FV},
671 {"infile", 1, NULL, OPT_INFILE},
672 {"datapubkey", 1, NULL, OPT_INFILE}, /* alias */
673 {"vmlinuz", 1, NULL, OPT_INFILE}, /* alias */
674 {"outfile", 1, NULL, OPT_OUTFILE},
675 {"bootloader", 1, NULL, OPT_BOOTLOADER},
676 {"config", 1, NULL, OPT_CONFIG},
677 {"arch", 1, NULL, OPT_ARCH},
678 {"kloadaddr", 1, NULL, OPT_KLOADADDR},
679 {"pad", 1, NULL, OPT_PADDING},
Bill Richardsonc540f592014-09-23 22:17:02 -0700680 {"pem_signpriv", 1, NULL, OPT_PEM_SIGNPRIV},
681 {"pem_algo", 1, NULL, OPT_PEM_ALGO},
682 {"pem_external", 1, NULL, OPT_PEM_EXTERNAL},
Bill Richardson5f2696d2014-09-23 22:03:56 -0700683 {"vblockonly", 0, &option.vblockonly, 1},
684 {"debug", 0, &debugging_enabled, 1},
685 {NULL, 0, NULL, 0},
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700686};
687static char *short_opts = ":s:b:k:S:B:v:f:d:l:";
688
689static int do_sign(int argc, char *argv[])
690{
691 char *infile = 0;
Bill Richardson5f2696d2014-09-23 22:03:56 -0700692 int i;
693 int ifd = -1;
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700694 int errorcnt = 0;
695 struct futil_traverse_state_s state;
Bill Richardsonb0f1cc52014-09-24 00:23:56 -0700696 uint8_t *buf;
697 uint32_t buf_len;
Bill Richardson5f2696d2014-09-23 22:03:56 -0700698 char *e = 0;
699 enum futil_file_type type;
700 int inout_file_count = 0;
701 int mapping;
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700702
703 opterr = 0; /* quiet, you */
704 while ((i = getopt_long(argc, argv, short_opts, long_opts, 0)) != -1) {
705 switch (i) {
706 case 's':
707 option.signprivate = PrivateKeyRead(optarg);
708 if (!option.signprivate) {
709 fprintf(stderr, "Error reading %s\n", optarg);
710 errorcnt++;
711 }
712 break;
713 case 'b':
714 option.keyblock = KeyBlockRead(optarg);
715 if (!option.keyblock) {
716 fprintf(stderr, "Error reading %s\n", optarg);
717 errorcnt++;
718 }
719 break;
720 case 'k':
721 option.kernel_subkey = PublicKeyRead(optarg);
722 if (!option.kernel_subkey) {
723 fprintf(stderr, "Error reading %s\n", optarg);
724 errorcnt++;
725 }
726 break;
727 case 'S':
728 option.devsignprivate = PrivateKeyRead(optarg);
729 if (!option.devsignprivate) {
730 fprintf(stderr, "Error reading %s\n", optarg);
731 errorcnt++;
732 }
733 break;
734 case 'B':
735 option.devkeyblock = KeyBlockRead(optarg);
736 if (!option.devkeyblock) {
737 fprintf(stderr, "Error reading %s\n", optarg);
738 errorcnt++;
739 }
740 break;
741 case 'v':
Bill Richardson5f2696d2014-09-23 22:03:56 -0700742 option.version_specified = 1;
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700743 option.version = strtoul(optarg, &e, 0);
744 if (!*optarg || (e && *e)) {
745 fprintf(stderr,
746 "Invalid --version \"%s\"\n", optarg);
747 errorcnt++;
748 }
749 break;
750
751 case 'f':
Bill Richardsona19b00d2014-09-04 23:20:43 -0700752 option.flags_specified = 1;
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700753 option.flags = strtoul(optarg, &e, 0);
754 if (!*optarg || (e && *e)) {
755 fprintf(stderr,
756 "Invalid --flags \"%s\"\n", optarg);
757 errorcnt++;
758 }
Bill Richardsona19b00d2014-09-04 23:20:43 -0700759 break;
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700760 case 'd':
761 option.loemdir = optarg;
762 break;
763 case 'l':
764 option.loemid = optarg;
765 break;
Bill Richardsonc540f592014-09-23 22:17:02 -0700766 case OPT_FV:
767 option.fv_specified = 1;
768 /* fallthrough */
Bill Richardson5f2696d2014-09-23 22:03:56 -0700769 case OPT_INFILE: /* aka "--vmlinuz" */
770 inout_file_count++;
771 infile = optarg;
772 break;
773 case OPT_OUTFILE:
774 inout_file_count++;
775 option.outfile = optarg;
776 break;
777 case OPT_BOOTLOADER:
778 option.bootloader_data = ReadFile(
779 optarg, &option.bootloader_size);
780 if (!option.bootloader_data) {
781 fprintf(stderr,
782 "Error reading bootloader file: %s\n",
783 strerror(errno));
784 errorcnt++;
785 }
786 Debug("bootloader file size=0x%" PRIx64 "\n",
787 option.bootloader_size);
788 break;
789 case OPT_CONFIG:
790 option.config_data = ReadConfigFile(
791 optarg, &option.config_size);
792 if (!option.config_data) {
793 fprintf(stderr,
794 "Error reading config file: %s\n",
795 strerror(errno));
796 errorcnt++;
797 }
798 break;
799 case OPT_ARCH:
800 /* check the first 3 characters to also match x86_64 */
801 if ((!strncasecmp(optarg, "x86", 3)) ||
802 (!strcasecmp(optarg, "amd64")))
803 option.arch = ARCH_X86;
804 else if ((!strcasecmp(optarg, "arm")) ||
805 (!strcasecmp(optarg, "aarch64")))
806 option.arch = ARCH_ARM;
807 else if (!strcasecmp(optarg, "mips"))
808 option.arch = ARCH_MIPS;
809 else {
810 fprintf(stderr,
811 "Unknown architecture: \"%s\"\n",
812 optarg);
813 errorcnt++;
814 }
815 break;
816 case OPT_KLOADADDR:
817 option.kloadaddr = strtoul(optarg, &e, 0);
818 if (!*optarg || (e && *e)) {
819 fprintf(stderr,
820 "Invalid --kloadaddr \"%s\"\n", optarg);
821 errorcnt++;
822 }
823 break;
824 case OPT_PADDING:
825 option.padding = strtoul(optarg, &e, 0);
826 if (!*optarg || (e && *e)) {
827 fprintf(stderr,
828 "Invalid --padding \"%s\"\n", optarg);
829 errorcnt++;
830 }
831 break;
Bill Richardsonc540f592014-09-23 22:17:02 -0700832 case OPT_PEM_SIGNPRIV:
833 option.pem_signpriv = optarg;
834 break;
835 case OPT_PEM_ALGO:
836 option.pem_algo_specified = 1;
837 option.pem_algo = strtoul(optarg, &e, 0);
838 if (!*optarg || (e && *e) ||
839 (option.pem_algo >= kNumAlgorithms)) {
840 fprintf(stderr,
841 "Invalid --pem_algo \"%s\"\n", optarg);
842 errorcnt++;
843 }
844 break;
845 case OPT_PEM_EXTERNAL:
846 option.pem_external = optarg;
847 break;
848
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700849 case '?':
850 if (optopt)
851 fprintf(stderr, "Unrecognized option: -%c\n",
852 optopt);
853 else
Bill Richardson5f2696d2014-09-23 22:03:56 -0700854 fprintf(stderr, "Unrecognized option: %s\n",
855 argv[optind - 1]);
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700856 errorcnt++;
857 break;
858 case ':':
859 fprintf(stderr, "Missing argument to -%c\n", optopt);
860 errorcnt++;
861 break;
Bill Richardson5f2696d2014-09-23 22:03:56 -0700862 case 0: /* handled option */
863 break;
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700864 default:
Bill Richardson5f2696d2014-09-23 22:03:56 -0700865 Debug("i=%d\n", i);
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700866 DIE;
867 }
868 }
869
Bill Richardson5f2696d2014-09-23 22:03:56 -0700870 /* If we don't have an input file already, we need one */
871 if (!infile) {
872 if (argc - optind <= 0) {
873 errorcnt++;
874 fprintf(stderr, "ERROR: missing input filename\n");
875 goto done;
876 } else {
877 inout_file_count++;
878 infile = argv[optind++];
879 }
880 }
881
882 /* What are we looking at? */
883 type = futil_what_file_type(infile);
884
885 /* We may be able to infer the type based on the other args */
886 if (type == FILE_TYPE_UNKNOWN) {
887 if (option.bootloader_data || option.config_data
888 || option.arch != ARCH_UNSPECIFIED)
889 type = FILE_TYPE_RAW_KERNEL;
Bill Richardsonc540f592014-09-23 22:17:02 -0700890 else if (option.kernel_subkey || option.fv_specified)
891 type = FILE_TYPE_RAW_FIRMWARE;
Bill Richardson5f2696d2014-09-23 22:03:56 -0700892 }
893
894 /* Check the arguments for the type of thing we want to sign */
895 switch (type) {
896 case FILE_TYPE_UNKNOWN:
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700897 fprintf(stderr,
Bill Richardson5f2696d2014-09-23 22:03:56 -0700898 "Unable to determine the type of the input file\n");
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700899 errorcnt++;
Bill Richardson5f2696d2014-09-23 22:03:56 -0700900 goto done;
Bill Richardsonc540f592014-09-23 22:17:02 -0700901 case FILE_TYPE_PUBKEY:
902 option.create_new_outfile = 1;
903 if (option.signprivate && option.pem_signpriv) {
904 fprintf(stderr,
905 "Only one of --signprivate and --pem_signpriv"
906 " can be specified\n");
907 errorcnt++;
908 }
909 if ((option.signprivate && option.pem_algo_specified) ||
910 (option.pem_signpriv && !option.pem_algo_specified)) {
911 fprintf(stderr, "--pem_algo must be used with"
912 " --pem_signpriv\n");
913 errorcnt++;
914 }
915 if (option.pem_external && !option.pem_signpriv) {
916 fprintf(stderr, "--pem_external must be used with"
917 " --pem_signpriv\n");
918 errorcnt++;
919 }
920 /* We'll wait to read the PEM file, since the external signer
921 * may want to read it instead. */
922 break;
Bill Richardson5f2696d2014-09-23 22:03:56 -0700923 case FILE_TYPE_KEYBLOCK:
924 fprintf(stderr, "Resigning a keyblock is kind of pointless.\n");
925 fprintf(stderr, "Just create a new one.\n");
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700926 errorcnt++;
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700927 break;
Bill Richardson5f2696d2014-09-23 22:03:56 -0700928 case FILE_TYPE_FW_PREAMBLE:
929 fprintf(stderr,
930 "%s IS a signature. Sign the firmware instead\n",
931 infile);
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700932 break;
Bill Richardson5f2696d2014-09-23 22:03:56 -0700933 case FILE_TYPE_GBB:
934 fprintf(stderr, "There's no way to sign a GBB\n");
935 errorcnt++;
936 break;
937 case FILE_TYPE_BIOS_IMAGE:
938 case FILE_TYPE_OLD_BIOS_IMAGE:
939 errorcnt += no_opt_if(!option.signprivate, "signprivate");
940 errorcnt += no_opt_if(!option.keyblock, "keyblock");
941 errorcnt += no_opt_if(!option.kernel_subkey, "kernelkey");
942 break;
943 case FILE_TYPE_KERN_PREAMBLE:
944 errorcnt += no_opt_if(!option.signprivate, "signprivate");
945 if (option.vblockonly)
946 option.create_new_outfile = 1;
947 break;
Bill Richardsonc540f592014-09-23 22:17:02 -0700948 case FILE_TYPE_RAW_FIRMWARE:
949 option.create_new_outfile = 1;
950 errorcnt += no_opt_if(!option.signprivate, "signprivate");
951 errorcnt += no_opt_if(!option.keyblock, "keyblock");
952 errorcnt += no_opt_if(!option.kernel_subkey, "kernelkey");
953 errorcnt += no_opt_if(!option.version_specified, "version");
954 break;
Bill Richardson5f2696d2014-09-23 22:03:56 -0700955 case FILE_TYPE_RAW_KERNEL:
956 option.create_new_outfile = 1;
957 errorcnt += no_opt_if(!option.signprivate, "signprivate");
958 errorcnt += no_opt_if(!option.keyblock, "keyblock");
959 errorcnt += no_opt_if(!option.version_specified, "version");
960 errorcnt += no_opt_if(!option.bootloader_data, "bootloader");
961 errorcnt += no_opt_if(!option.config_data, "config");
962 errorcnt += no_opt_if(option.arch == ARCH_UNSPECIFIED, "arch");
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700963 break;
964 default:
Bill Richardson5f2696d2014-09-23 22:03:56 -0700965 DIE;
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700966 }
967
Bill Richardson5f2696d2014-09-23 22:03:56 -0700968 /* If we don't have an output file, we may need one */
969 if (!option.outfile) {
970 if (argc - optind > 0) {
971 /* We have an outfile arg, so use it. */
972 inout_file_count++;
973 option.outfile = argv[optind++];
974 } else {
975 if (option.create_new_outfile) {
976 /* A distinct outfile is required */
977 errorcnt++;
978 fprintf(stderr, "Missing output filename\n");
979 goto done;
980 } else {
981 /* We'll just modify the input file */
982 option.outfile = infile;
983 }
984 }
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700985 }
986
Bill Richardson5f2696d2014-09-23 22:03:56 -0700987 Debug("type=%d\n", type);
988 Debug("option.create_new_outfile=%d\n", option.create_new_outfile);
989 Debug("inout_file_count=%d\n", inout_file_count);
990 Debug("infile=%s\n", infile);
991 Debug("option.outfile=%s\n", option.outfile);
992
993 if (argc - optind > 0) {
Bill Richardsonb0f1cc52014-09-24 00:23:56 -0700994 errorcnt++;
Bill Richardson5f2696d2014-09-23 22:03:56 -0700995 fprintf(stderr, "ERROR: too many arguments left over\n");
Bill Richardsonb0f1cc52014-09-24 00:23:56 -0700996 }
997
Bill Richardson5f2696d2014-09-23 22:03:56 -0700998 if (errorcnt)
999 goto done;
1000
Bill Richardson15dc6fc2014-09-02 14:45:44 -07001001 memset(&state, 0, sizeof(state));
Bill Richardson15dc6fc2014-09-02 14:45:44 -07001002 state.op = FUTIL_OP_SIGN;
1003
Bill Richardson5f2696d2014-09-23 22:03:56 -07001004 if (option.create_new_outfile) {
1005 /* The input is read-only, the output is write-only. */
1006 mapping = MAP_RO;
1007 state.in_filename = infile;
1008 ifd = open(infile, O_RDONLY);
1009 if (ifd < 0) {
1010 errorcnt++;
1011 fprintf(stderr, "Can't open %s for reading: %s\n",
1012 infile, strerror(errno));
1013 goto done;
1014 }
1015 } else {
1016 /* We'll read-modify-write the output file */
1017 mapping = MAP_RW;
1018 state.in_filename = option.outfile;
1019 if (inout_file_count > 1)
1020 futil_copy_file_or_die(infile, option.outfile);
1021 ifd = open(option.outfile, O_RDWR);
1022 if (ifd < 0) {
1023 errorcnt++;
1024 fprintf(stderr, "Can't open %s for writing: %s\n",
1025 option.outfile, strerror(errno));
1026 goto done;
1027 }
1028 }
Bill Richardson15dc6fc2014-09-02 14:45:44 -07001029
Bill Richardson5f2696d2014-09-23 22:03:56 -07001030 if (0 != futil_map_file(ifd, mapping, &buf, &buf_len)) {
Bill Richardson15dc6fc2014-09-02 14:45:44 -07001031 errorcnt++;
Bill Richardson5f2696d2014-09-23 22:03:56 -07001032 goto done;
1033 }
1034
1035 errorcnt += futil_traverse(buf, buf_len, &state, type);
1036
1037 errorcnt += futil_unmap_file(ifd, MAP_RW, buf, buf_len);
1038
1039done:
1040 if (ifd >= 0 && close(ifd)) {
1041 errorcnt++;
1042 fprintf(stderr, "Error when closing ifd: %s\n",
1043 strerror(errno));
Bill Richardson15dc6fc2014-09-02 14:45:44 -07001044 }
1045
1046 if (option.signprivate)
1047 free(option.signprivate);
1048 if (option.keyblock)
1049 free(option.keyblock);
1050 if (option.kernel_subkey)
1051 free(option.kernel_subkey);
1052
Bill Richardson5f2696d2014-09-23 22:03:56 -07001053 if (errorcnt)
1054 fprintf(stderr, "Use --help for usage instructions\n");
1055
Bill Richardson15dc6fc2014-09-02 14:45:44 -07001056 return !!errorcnt;
1057}
1058
Bill Richardson779796f2014-09-23 11:47:40 -07001059DECLARE_FUTIL_COMMAND(sign, do_sign,
Bill Richardson5f2696d2014-09-23 22:03:56 -07001060 "Sign / resign various binary components",
Bill Richardson779796f2014-09-23 11:47:40 -07001061 print_help);