blob: f256b00eee8a909ef03ee353f28525daea3f2c55 [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
Bill Richardsonb406c102014-12-03 14:10:13 -0800305 if (option.create_new_outfile) {
306 /* Write out what we've been asked for */
307 if (option.vblockonly)
308 rv = WriteSomeParts(option.outfile,
309 vblock_data, vblock_size,
310 NULL, 0);
311 else
312 rv = WriteSomeParts(option.outfile,
313 vblock_data, vblock_size,
314 kblob_data, kblob_size);
Bill Richardson5f2696d2014-09-23 22:03:56 -0700315 } else {
Bill Richardsonb406c102014-12-03 14:10:13 -0800316 /* If we're modifying an existing file, it's mmap'ed so that
317 * all our modifications to the buffer will get flushed to
318 * disk when we close it. */
Bill Richardson5f2696d2014-09-23 22:03:56 -0700319 Memcpy(kpart_data, vblock_data, vblock_size);
320 }
321
322 free(vblock_data);
323 return rv;
324}
325
326
327int futil_cb_sign_raw_firmware(struct futil_traverse_state_s *state)
328{
Bill Richardsonc540f592014-09-23 22:17:02 -0700329 VbSignature *body_sig;
330 VbFirmwarePreambleHeader *preamble;
331 int rv;
332
333 body_sig = CalculateSignature(state->my_area->buf, state->my_area->len,
334 option.signprivate);
335 if (!body_sig) {
336 fprintf(stderr, "Error calculating body signature\n");
337 return 1;
338 }
339
340 preamble = CreateFirmwarePreamble(option.version,
341 option.kernel_subkey,
342 body_sig,
343 option.signprivate,
344 option.flags);
345 if (!preamble) {
346 fprintf(stderr, "Error creating firmware preamble.\n");
347 free(body_sig);
348 return 1;
349 }
350
351 rv = WriteSomeParts(option.outfile,
352 option.keyblock, option.keyblock->key_block_size,
353 preamble, preamble->preamble_size);
354
355 free(preamble);
356 free(body_sig);
357
358 return rv;
Bill Richardson5f2696d2014-09-23 22:03:56 -0700359}
360
361
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700362int futil_cb_sign_begin(struct futil_traverse_state_s *state)
363{
364 if (state->in_type == FILE_TYPE_UNKNOWN) {
365 fprintf(stderr, "Unable to determine type of %s\n",
366 state->in_filename);
367 return 1;
368 }
369
370 return 0;
371}
372
373static int write_new_preamble(struct cb_area_s *vblock,
374 struct cb_area_s *fw_body,
375 VbPrivateKey *signkey,
376 VbKeyBlockHeader *keyblock)
377{
378 VbSignature *body_sig;
379 VbFirmwarePreambleHeader *preamble;
380
381 body_sig = CalculateSignature(fw_body->buf, fw_body->len, signkey);
382 if (!body_sig) {
383 fprintf(stderr, "Error calculating body signature\n");
384 return 1;
385 }
386
387 preamble = CreateFirmwarePreamble(option.version,
388 option.kernel_subkey,
389 body_sig,
390 signkey,
391 option.flags);
392 if (!preamble) {
393 fprintf(stderr, "Error creating firmware preamble.\n");
394 free(body_sig);
395 return 1;
396 }
397
398 /* Write the new keyblock */
399 uint32_t more = keyblock->key_block_size;
400 memcpy(vblock->buf, keyblock, more);
401 /* and the new preamble */
402 memcpy(vblock->buf + more, preamble, preamble->preamble_size);
403
404 free(preamble);
405 free(body_sig);
406
407 return 0;
408}
409
410static int write_loem(const char *ab, struct cb_area_s *vblock)
411{
412 char filename[PATH_MAX];
413 int n;
414 n = snprintf(filename, sizeof(filename), "%s/vblock_%s.%s",
415 option.loemdir ? option.loemdir : ".",
416 ab, option.loemid);
417 if (n >= sizeof(filename)) {
418 fprintf(stderr, "LOEM args produce bogus filename\n");
419 return 1;
420 }
421
422 FILE *fp = fopen(filename, "w");
423 if (!fp) {
424 fprintf(stderr, "Can't open %s for writing: %s\n",
425 filename, strerror(errno));
426 return 1;
427 }
428
429 if (1 != fwrite(vblock->buf, vblock->len, 1, fp)) {
430 fprintf(stderr, "Can't write to %s: %s\n",
431 filename, strerror(errno));
432 fclose(fp);
433 return 1;
434 }
435 if (fclose(fp)) {
436 fprintf(stderr, "Failed closing loem output: %s\n",
437 strerror(errno));
438 return 1;
439 }
440
441 return 0;
442}
443
Bill Richardson5f2696d2014-09-23 22:03:56 -0700444/* This signs a full BIOS image after it's been traversed. */
445static int sign_bios_at_end(struct futil_traverse_state_s *state)
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700446{
447 struct cb_area_s *vblock_a = &state->cb_area[CB_FMAP_VBLOCK_A];
448 struct cb_area_s *vblock_b = &state->cb_area[CB_FMAP_VBLOCK_B];
449 struct cb_area_s *fw_a = &state->cb_area[CB_FMAP_FW_MAIN_A];
450 struct cb_area_s *fw_b = &state->cb_area[CB_FMAP_FW_MAIN_B];
451 int retval = 0;
452
453 if (state->errors ||
454 !(vblock_a->_flags & AREA_IS_VALID) ||
455 !(vblock_b->_flags & AREA_IS_VALID) ||
456 !(fw_a->_flags & AREA_IS_VALID) ||
457 !(fw_b->_flags & AREA_IS_VALID)) {
458 fprintf(stderr, "Something's wrong. Not changing anything\n");
459 return 1;
460 }
461
462 /* Do A & B differ ? */
463 if (fw_a->len != fw_b->len ||
464 memcmp(fw_a->buf, fw_b->buf, fw_a->len)) {
465 /* Yes, must use DEV keys for A */
466 if (!option.devsignprivate || !option.devkeyblock) {
467 fprintf(stderr,
468 "FW A & B differ. DEV keys are required.\n");
469 return 1;
470 }
471 retval |= write_new_preamble(vblock_a, fw_a,
472 option.devsignprivate,
473 option.devkeyblock);
474 } else {
475 retval |= write_new_preamble(vblock_a, fw_a,
476 option.signprivate,
477 option.keyblock);
478 }
479
480 /* FW B is always normal keys */
481 retval |= write_new_preamble(vblock_b, fw_b,
482 option.signprivate,
483 option.keyblock);
484
485
486
487
488 if (option.loemid) {
489 retval |= write_loem("A", vblock_a);
490 retval |= write_loem("B", vblock_b);
491 }
492
493 return retval;
494}
495
Bill Richardson5f2696d2014-09-23 22:03:56 -0700496int futil_cb_sign_end(struct futil_traverse_state_s *state)
497{
498 switch (state->in_type) {
499 case FILE_TYPE_BIOS_IMAGE:
500 case FILE_TYPE_OLD_BIOS_IMAGE:
501 return sign_bios_at_end(state);
502
503 default:
504 /* Any other cleanup needed? */
505 break;
506 }
507
508 return state->errors;
509}
510
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700511static const char usage[] = "\n"
Bill Richardson5f2696d2014-09-23 22:03:56 -0700512 "Usage: " MYNAME " %s [PARAMS] INFILE [OUTFILE]\n"
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700513 "\n"
Bill Richardson5f2696d2014-09-23 22:03:56 -0700514 "Where INFILE is a\n"
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700515 "\n"
Bill Richardsonc540f592014-09-23 22:17:02 -0700516 " public key (.vbpubk); OUTFILE is a keyblock\n"
517 " raw firmware blob (FW_MAIN_A/B); OUTFILE is a VBLOCK_A/B\n"
Bill Richardson5f2696d2014-09-23 22:03:56 -0700518 " complete firmware image (bios.bin)\n"
519 " raw linux kernel; OUTFILE is a kernel partition image\n"
520 " kernel partition image (/dev/sda2, /dev/mmcblk0p2)\n";
521
Bill Richardsonc540f592014-09-23 22:17:02 -0700522static const char usage_pubkey[] = "\n"
523 "-----------------------------------------------------------------\n"
524 "To sign a public key / create a new keyblock:\n"
525 "\n"
526 "Required PARAMS:\n"
527 " [--datapubkey] INFILE The public key to wrap\n"
528 " [--outfile] OUTFILE The resulting keyblock\n"
529 "\n"
530 "Optional PARAMS:\n"
531 " A private signing key, specified as either\n"
532 " -s|--signprivate FILE.vbprivk Signing key in .vbprivk format\n"
533 " Or\n"
534 " --pem_signpriv FILE.pem Signing key in PEM format...\n"
535 " --pem_algo NUM AND the algorithm to use (0 - %d)\n"
536 "\n"
537 " If a signing key is not given, the keyblock will not be signed (duh)."
538 "\n\n"
539 "And these, too:\n\n"
540 " -f|--flags NUM Flags specifying use conditions\n"
541 " --pem_external PROGRAM"
542 " External program to compute the signature\n"
543 " (requires a PEM signing key)\n";
544
545static const char usage_fw_main[] = "\n"
546 "-----------------------------------------------------------------\n"
547 "To sign a raw firmware blob (FW_MAIN_A/B):\n"
548 "\n"
549 "Required PARAMS:\n"
550 " -s|--signprivate FILE.vbprivk The private firmware data key\n"
551 " -b|--keyblock FILE.keyblock The keyblock containing the\n"
552 " public firmware data key\n"
553 " -k|--kernelkey FILE.vbpubk The public kernel subkey\n"
554 " -v|--version NUM The firmware version number\n"
555 " [--fv] INFILE"
556 " The raw firmware blob (FW_MAIN_A/B)\n"
557 " [--outfile] OUTFILE Output VBLOCK_A/B\n"
558 "\n"
559 "Optional PARAMS:\n"
560 " -f|--flags NUM The preamble flags value"
561 " (default is 0)\n";
562
Bill Richardson5f2696d2014-09-23 22:03:56 -0700563static const char usage_bios[] = "\n"
564 "-----------------------------------------------------------------\n"
565 "To sign a complete firmware image (bios.bin):\n"
566 "\n"
567 "Required PARAMS:\n"
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700568 " -s|--signprivate FILE.vbprivk The private firmware data key\n"
569 " -b|--keyblock FILE.keyblock The keyblock containing the\n"
570 " public firmware data key\n"
571 " -k|--kernelkey FILE.vbpubk The public kernel subkey\n"
Bill Richardson5f2696d2014-09-23 22:03:56 -0700572 " [--infile] INFILE Input firmware image (modified\n"
573 " in place if no OUTFILE given)\n"
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700574 "\n"
575 "These are required if the A and B firmware differ:\n"
576 " -S|--devsign FILE.vbprivk The DEV private firmware data key\n"
577 " -B|--devkeyblock FILE.keyblock The keyblock containing the\n"
578 " DEV public firmware data key\n"
579 "\n"
Bill Richardson5f2696d2014-09-23 22:03:56 -0700580 "Optional PARAMS:\n"
Bill Richardson08efd1e2014-09-04 22:53:41 -0700581 " -v|--version NUM The firmware version number"
582 " (default %d)\n"
583 " -f|--flags NUM The preamble flags value"
584 " (default is\n"
585 " unchanged, or 0 if unknown)\n"
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700586 " -d|--loemdir DIR Local OEM output vblock directory\n"
587 " -l|--loemid STRING Local OEM vblock suffix\n"
Bill Richardson5f2696d2014-09-23 22:03:56 -0700588 " [--outfile] OUTFILE Output firmware image\n";
589
590static const char usage_new_kpart[] = "\n"
591 "-----------------------------------------------------------------\n"
592 "To create a new kernel parition image (/dev/sda2, /dev/mmcblk0p2):\n"
593 "\n"
594 "Required PARAMS:\n"
595 " -s|--signprivate FILE.vbprivk"
596 " The private key to sign the kernel blob\n"
597 " -b|--keyblock FILE.keyblock The keyblock containing the public\n"
598 " key to verify the kernel blob\n"
599 " -v|--version NUM The kernel version number\n"
600 " --bootloader FILE Bootloader stub\n"
601 " --config FILE The kernel commandline file\n"
602 " --arch ARCH The CPU architecture (one of\n"
603 " x86|amd64, arm|aarch64, mips)\n"
604 " [--vmlinuz] INFILE Linux kernel bzImage file\n"
605 " [--outfile] OUTFILE Output kernel partition or vblock\n"
606 "\n"
607 "Optional PARAMS:\n"
608 " --kloadaddr NUM"
609 " RAM address to load the kernel body\n"
610 " (default 0x%x)\n"
611 " --pad NUM The vblock padding size in bytes\n"
612 " (default 0x%x)\n"
613 " --vblockonly Emit just the vblock (requires a\n"
614 " distinct outfile)\n";
615
616static const char usage_old_kpart[] = "\n"
617 "-----------------------------------------------------------------\n"
618 "To resign an existing kernel parition (/dev/sda2, /dev/mmcblk0p2):\n"
619 "\n"
620 "Required PARAMS:\n"
621 " -s|--signprivate FILE.vbprivk"
622 " The private key to sign the kernel blob\n"
623 " [--infile] INFILE Input kernel partition (modified\n"
624 " in place if no OUTFILE given)\n"
625 "\n"
626 "Optional PARAMS:\n"
627 " -b|--keyblock FILE.keyblock The keyblock containing the public\n"
628 " key to verify the kernel blob\n"
629 " -v|--version NUM The kernel version number\n"
630 " --config FILE The kernel commandline file\n"
631 " --pad NUM The vblock padding size in bytes\n"
632 " (default 0x%x)\n"
633 " [--outfile] OUTFILE Output kernel partition or vblock\n"
634 " --vblockonly Emit just the vblock (requires a\n"
635 " distinct OUTFILE)\n"
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700636 "\n";
637
Bill Richardson779796f2014-09-23 11:47:40 -0700638static void print_help(const char *prog)
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700639{
Bill Richardson5f2696d2014-09-23 22:03:56 -0700640 printf(usage, prog);
Bill Richardsonc540f592014-09-23 22:17:02 -0700641 printf(usage_pubkey, kNumAlgorithms - 1);
642 puts(usage_fw_main);
Bill Richardson5f2696d2014-09-23 22:03:56 -0700643 printf(usage_bios, option.version);
644 printf(usage_new_kpart, option.kloadaddr, option.padding);
645 printf(usage_old_kpart, option.padding);
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700646}
647
Bill Richardson5f2696d2014-09-23 22:03:56 -0700648enum no_short_opts {
649 OPT_FV = 1000,
650 OPT_INFILE, /* aka "--vmlinuz" */
651 OPT_OUTFILE,
652 OPT_BOOTLOADER,
653 OPT_CONFIG,
654 OPT_ARCH,
655 OPT_KLOADADDR,
656 OPT_PADDING,
Bill Richardsonc540f592014-09-23 22:17:02 -0700657 OPT_PEM_SIGNPRIV,
658 OPT_PEM_ALGO,
659 OPT_PEM_EXTERNAL,
Bill Richardson5f2696d2014-09-23 22:03:56 -0700660};
661
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700662static const struct option long_opts[] = {
663 /* name hasarg *flag val */
Bill Richardson5f2696d2014-09-23 22:03:56 -0700664 {"signprivate", 1, NULL, 's'},
665 {"keyblock", 1, NULL, 'b'},
666 {"kernelkey", 1, NULL, 'k'},
667 {"devsign", 1, NULL, 'S'},
668 {"devkeyblock", 1, NULL, 'B'},
669 {"version", 1, NULL, 'v'},
670 {"flags", 1, NULL, 'f'},
671 {"loemdir", 1, NULL, 'd'},
672 {"loemid", 1, NULL, 'l'},
673 {"fv", 1, NULL, OPT_FV},
674 {"infile", 1, NULL, OPT_INFILE},
675 {"datapubkey", 1, NULL, OPT_INFILE}, /* alias */
676 {"vmlinuz", 1, NULL, OPT_INFILE}, /* alias */
677 {"outfile", 1, NULL, OPT_OUTFILE},
678 {"bootloader", 1, NULL, OPT_BOOTLOADER},
679 {"config", 1, NULL, OPT_CONFIG},
680 {"arch", 1, NULL, OPT_ARCH},
681 {"kloadaddr", 1, NULL, OPT_KLOADADDR},
682 {"pad", 1, NULL, OPT_PADDING},
Bill Richardsonc540f592014-09-23 22:17:02 -0700683 {"pem_signpriv", 1, NULL, OPT_PEM_SIGNPRIV},
684 {"pem_algo", 1, NULL, OPT_PEM_ALGO},
685 {"pem_external", 1, NULL, OPT_PEM_EXTERNAL},
Bill Richardson5f2696d2014-09-23 22:03:56 -0700686 {"vblockonly", 0, &option.vblockonly, 1},
687 {"debug", 0, &debugging_enabled, 1},
688 {NULL, 0, NULL, 0},
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700689};
690static char *short_opts = ":s:b:k:S:B:v:f:d:l:";
691
692static int do_sign(int argc, char *argv[])
693{
694 char *infile = 0;
Bill Richardson5f2696d2014-09-23 22:03:56 -0700695 int i;
696 int ifd = -1;
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700697 int errorcnt = 0;
698 struct futil_traverse_state_s state;
Bill Richardsonb0f1cc52014-09-24 00:23:56 -0700699 uint8_t *buf;
700 uint32_t buf_len;
Bill Richardson5f2696d2014-09-23 22:03:56 -0700701 char *e = 0;
702 enum futil_file_type type;
703 int inout_file_count = 0;
704 int mapping;
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700705
706 opterr = 0; /* quiet, you */
707 while ((i = getopt_long(argc, argv, short_opts, long_opts, 0)) != -1) {
708 switch (i) {
709 case 's':
710 option.signprivate = PrivateKeyRead(optarg);
711 if (!option.signprivate) {
712 fprintf(stderr, "Error reading %s\n", optarg);
713 errorcnt++;
714 }
715 break;
716 case 'b':
717 option.keyblock = KeyBlockRead(optarg);
718 if (!option.keyblock) {
719 fprintf(stderr, "Error reading %s\n", optarg);
720 errorcnt++;
721 }
722 break;
723 case 'k':
724 option.kernel_subkey = PublicKeyRead(optarg);
725 if (!option.kernel_subkey) {
726 fprintf(stderr, "Error reading %s\n", optarg);
727 errorcnt++;
728 }
729 break;
730 case 'S':
731 option.devsignprivate = PrivateKeyRead(optarg);
732 if (!option.devsignprivate) {
733 fprintf(stderr, "Error reading %s\n", optarg);
734 errorcnt++;
735 }
736 break;
737 case 'B':
738 option.devkeyblock = KeyBlockRead(optarg);
739 if (!option.devkeyblock) {
740 fprintf(stderr, "Error reading %s\n", optarg);
741 errorcnt++;
742 }
743 break;
744 case 'v':
Bill Richardson5f2696d2014-09-23 22:03:56 -0700745 option.version_specified = 1;
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700746 option.version = strtoul(optarg, &e, 0);
747 if (!*optarg || (e && *e)) {
748 fprintf(stderr,
749 "Invalid --version \"%s\"\n", optarg);
750 errorcnt++;
751 }
752 break;
753
754 case 'f':
Bill Richardsona19b00d2014-09-04 23:20:43 -0700755 option.flags_specified = 1;
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700756 option.flags = strtoul(optarg, &e, 0);
757 if (!*optarg || (e && *e)) {
758 fprintf(stderr,
759 "Invalid --flags \"%s\"\n", optarg);
760 errorcnt++;
761 }
Bill Richardsona19b00d2014-09-04 23:20:43 -0700762 break;
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700763 case 'd':
764 option.loemdir = optarg;
765 break;
766 case 'l':
767 option.loemid = optarg;
768 break;
Bill Richardsonc540f592014-09-23 22:17:02 -0700769 case OPT_FV:
770 option.fv_specified = 1;
771 /* fallthrough */
Bill Richardson5f2696d2014-09-23 22:03:56 -0700772 case OPT_INFILE: /* aka "--vmlinuz" */
773 inout_file_count++;
774 infile = optarg;
775 break;
776 case OPT_OUTFILE:
777 inout_file_count++;
778 option.outfile = optarg;
779 break;
780 case OPT_BOOTLOADER:
781 option.bootloader_data = ReadFile(
782 optarg, &option.bootloader_size);
783 if (!option.bootloader_data) {
784 fprintf(stderr,
785 "Error reading bootloader file: %s\n",
786 strerror(errno));
787 errorcnt++;
788 }
789 Debug("bootloader file size=0x%" PRIx64 "\n",
790 option.bootloader_size);
791 break;
792 case OPT_CONFIG:
793 option.config_data = ReadConfigFile(
794 optarg, &option.config_size);
795 if (!option.config_data) {
796 fprintf(stderr,
797 "Error reading config file: %s\n",
798 strerror(errno));
799 errorcnt++;
800 }
801 break;
802 case OPT_ARCH:
803 /* check the first 3 characters to also match x86_64 */
804 if ((!strncasecmp(optarg, "x86", 3)) ||
805 (!strcasecmp(optarg, "amd64")))
806 option.arch = ARCH_X86;
807 else if ((!strcasecmp(optarg, "arm")) ||
808 (!strcasecmp(optarg, "aarch64")))
809 option.arch = ARCH_ARM;
810 else if (!strcasecmp(optarg, "mips"))
811 option.arch = ARCH_MIPS;
812 else {
813 fprintf(stderr,
814 "Unknown architecture: \"%s\"\n",
815 optarg);
816 errorcnt++;
817 }
818 break;
819 case OPT_KLOADADDR:
820 option.kloadaddr = strtoul(optarg, &e, 0);
821 if (!*optarg || (e && *e)) {
822 fprintf(stderr,
823 "Invalid --kloadaddr \"%s\"\n", optarg);
824 errorcnt++;
825 }
826 break;
827 case OPT_PADDING:
828 option.padding = strtoul(optarg, &e, 0);
829 if (!*optarg || (e && *e)) {
830 fprintf(stderr,
831 "Invalid --padding \"%s\"\n", optarg);
832 errorcnt++;
833 }
834 break;
Bill Richardsonc540f592014-09-23 22:17:02 -0700835 case OPT_PEM_SIGNPRIV:
836 option.pem_signpriv = optarg;
837 break;
838 case OPT_PEM_ALGO:
839 option.pem_algo_specified = 1;
840 option.pem_algo = strtoul(optarg, &e, 0);
841 if (!*optarg || (e && *e) ||
842 (option.pem_algo >= kNumAlgorithms)) {
843 fprintf(stderr,
844 "Invalid --pem_algo \"%s\"\n", optarg);
845 errorcnt++;
846 }
847 break;
848 case OPT_PEM_EXTERNAL:
849 option.pem_external = optarg;
850 break;
851
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700852 case '?':
853 if (optopt)
854 fprintf(stderr, "Unrecognized option: -%c\n",
855 optopt);
856 else
Bill Richardson5f2696d2014-09-23 22:03:56 -0700857 fprintf(stderr, "Unrecognized option: %s\n",
858 argv[optind - 1]);
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700859 errorcnt++;
860 break;
861 case ':':
862 fprintf(stderr, "Missing argument to -%c\n", optopt);
863 errorcnt++;
864 break;
Bill Richardson5f2696d2014-09-23 22:03:56 -0700865 case 0: /* handled option */
866 break;
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700867 default:
Bill Richardson5f2696d2014-09-23 22:03:56 -0700868 Debug("i=%d\n", i);
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700869 DIE;
870 }
871 }
872
Bill Richardson5f2696d2014-09-23 22:03:56 -0700873 /* If we don't have an input file already, we need one */
874 if (!infile) {
875 if (argc - optind <= 0) {
876 errorcnt++;
877 fprintf(stderr, "ERROR: missing input filename\n");
878 goto done;
879 } else {
880 inout_file_count++;
881 infile = argv[optind++];
882 }
883 }
884
Bill Richardsonb406c102014-12-03 14:10:13 -0800885 /* Look for an output file if we don't have one, just in case. */
886 if (!option.outfile && argc - optind > 0) {
887 inout_file_count++;
888 option.outfile = argv[optind++];
889 }
890
Bill Richardson5f2696d2014-09-23 22:03:56 -0700891 /* What are we looking at? */
892 type = futil_what_file_type(infile);
893
894 /* We may be able to infer the type based on the other args */
895 if (type == FILE_TYPE_UNKNOWN) {
896 if (option.bootloader_data || option.config_data
897 || option.arch != ARCH_UNSPECIFIED)
898 type = FILE_TYPE_RAW_KERNEL;
Bill Richardsonc540f592014-09-23 22:17:02 -0700899 else if (option.kernel_subkey || option.fv_specified)
900 type = FILE_TYPE_RAW_FIRMWARE;
Bill Richardson5f2696d2014-09-23 22:03:56 -0700901 }
902
Bill Richardsonb406c102014-12-03 14:10:13 -0800903 Debug("type=%s\n", futil_file_type_str[type]);
904
Bill Richardson5f2696d2014-09-23 22:03:56 -0700905 /* Check the arguments for the type of thing we want to sign */
906 switch (type) {
907 case FILE_TYPE_UNKNOWN:
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700908 fprintf(stderr,
Bill Richardson5f2696d2014-09-23 22:03:56 -0700909 "Unable to determine the type of the input file\n");
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700910 errorcnt++;
Bill Richardson5f2696d2014-09-23 22:03:56 -0700911 goto done;
Bill Richardsonc540f592014-09-23 22:17:02 -0700912 case FILE_TYPE_PUBKEY:
913 option.create_new_outfile = 1;
914 if (option.signprivate && option.pem_signpriv) {
915 fprintf(stderr,
916 "Only one of --signprivate and --pem_signpriv"
917 " can be specified\n");
918 errorcnt++;
919 }
920 if ((option.signprivate && option.pem_algo_specified) ||
921 (option.pem_signpriv && !option.pem_algo_specified)) {
922 fprintf(stderr, "--pem_algo must be used with"
923 " --pem_signpriv\n");
924 errorcnt++;
925 }
926 if (option.pem_external && !option.pem_signpriv) {
927 fprintf(stderr, "--pem_external must be used with"
928 " --pem_signpriv\n");
929 errorcnt++;
930 }
931 /* We'll wait to read the PEM file, since the external signer
932 * may want to read it instead. */
933 break;
Bill Richardson5f2696d2014-09-23 22:03:56 -0700934 case FILE_TYPE_KEYBLOCK:
935 fprintf(stderr, "Resigning a keyblock is kind of pointless.\n");
936 fprintf(stderr, "Just create a new one.\n");
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700937 errorcnt++;
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700938 break;
Bill Richardson5f2696d2014-09-23 22:03:56 -0700939 case FILE_TYPE_FW_PREAMBLE:
940 fprintf(stderr,
941 "%s IS a signature. Sign the firmware instead\n",
942 infile);
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700943 break;
Bill Richardson5f2696d2014-09-23 22:03:56 -0700944 case FILE_TYPE_GBB:
945 fprintf(stderr, "There's no way to sign a GBB\n");
946 errorcnt++;
947 break;
948 case FILE_TYPE_BIOS_IMAGE:
949 case FILE_TYPE_OLD_BIOS_IMAGE:
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 break;
954 case FILE_TYPE_KERN_PREAMBLE:
955 errorcnt += no_opt_if(!option.signprivate, "signprivate");
Bill Richardsonb406c102014-12-03 14:10:13 -0800956 if (option.vblockonly || inout_file_count > 1)
Bill Richardson5f2696d2014-09-23 22:03:56 -0700957 option.create_new_outfile = 1;
958 break;
Bill Richardsonc540f592014-09-23 22:17:02 -0700959 case FILE_TYPE_RAW_FIRMWARE:
960 option.create_new_outfile = 1;
961 errorcnt += no_opt_if(!option.signprivate, "signprivate");
962 errorcnt += no_opt_if(!option.keyblock, "keyblock");
963 errorcnt += no_opt_if(!option.kernel_subkey, "kernelkey");
964 errorcnt += no_opt_if(!option.version_specified, "version");
965 break;
Bill Richardson5f2696d2014-09-23 22:03:56 -0700966 case FILE_TYPE_RAW_KERNEL:
967 option.create_new_outfile = 1;
968 errorcnt += no_opt_if(!option.signprivate, "signprivate");
969 errorcnt += no_opt_if(!option.keyblock, "keyblock");
970 errorcnt += no_opt_if(!option.version_specified, "version");
971 errorcnt += no_opt_if(!option.bootloader_data, "bootloader");
972 errorcnt += no_opt_if(!option.config_data, "config");
973 errorcnt += no_opt_if(option.arch == ARCH_UNSPECIFIED, "arch");
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700974 break;
975 default:
Bill Richardson5f2696d2014-09-23 22:03:56 -0700976 DIE;
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700977 }
978
Bill Richardsonb406c102014-12-03 14:10:13 -0800979 Debug("infile=%s\n", infile);
980 Debug("inout_file_count=%d\n", inout_file_count);
981 Debug("option.create_new_outfile=%d\n", option.create_new_outfile);
982
983 /* Make sure we have an output file if one is needed */
Bill Richardson5f2696d2014-09-23 22:03:56 -0700984 if (!option.outfile) {
Bill Richardsonb406c102014-12-03 14:10:13 -0800985 if (option.create_new_outfile) {
986 errorcnt++;
987 fprintf(stderr, "Missing output filename\n");
988 goto done;
Bill Richardson5f2696d2014-09-23 22:03:56 -0700989 } else {
Bill Richardsonb406c102014-12-03 14:10:13 -0800990 option.outfile = infile;
Bill Richardson5f2696d2014-09-23 22:03:56 -0700991 }
Bill Richardson15dc6fc2014-09-02 14:45:44 -0700992 }
993
Bill Richardson5f2696d2014-09-23 22:03:56 -0700994 Debug("option.outfile=%s\n", option.outfile);
995
996 if (argc - optind > 0) {
Bill Richardsonb0f1cc52014-09-24 00:23:56 -0700997 errorcnt++;
Bill Richardson5f2696d2014-09-23 22:03:56 -0700998 fprintf(stderr, "ERROR: too many arguments left over\n");
Bill Richardsonb0f1cc52014-09-24 00:23:56 -0700999 }
1000
Bill Richardson5f2696d2014-09-23 22:03:56 -07001001 if (errorcnt)
1002 goto done;
1003
Bill Richardson15dc6fc2014-09-02 14:45:44 -07001004 memset(&state, 0, sizeof(state));
Bill Richardson15dc6fc2014-09-02 14:45:44 -07001005 state.op = FUTIL_OP_SIGN;
1006
Bill Richardson5f2696d2014-09-23 22:03:56 -07001007 if (option.create_new_outfile) {
1008 /* The input is read-only, the output is write-only. */
1009 mapping = MAP_RO;
1010 state.in_filename = infile;
Bill Richardsonb406c102014-12-03 14:10:13 -08001011 Debug("open RO %s\n", infile);
Bill Richardson5f2696d2014-09-23 22:03:56 -07001012 ifd = open(infile, O_RDONLY);
1013 if (ifd < 0) {
1014 errorcnt++;
1015 fprintf(stderr, "Can't open %s for reading: %s\n",
1016 infile, strerror(errno));
1017 goto done;
1018 }
1019 } else {
1020 /* We'll read-modify-write the output file */
1021 mapping = MAP_RW;
1022 state.in_filename = option.outfile;
1023 if (inout_file_count > 1)
1024 futil_copy_file_or_die(infile, option.outfile);
Bill Richardsonb406c102014-12-03 14:10:13 -08001025 Debug("open RW %s\n", option.outfile);
Bill Richardson5f2696d2014-09-23 22:03:56 -07001026 ifd = open(option.outfile, O_RDWR);
1027 if (ifd < 0) {
1028 errorcnt++;
1029 fprintf(stderr, "Can't open %s for writing: %s\n",
1030 option.outfile, strerror(errno));
1031 goto done;
1032 }
1033 }
Bill Richardson15dc6fc2014-09-02 14:45:44 -07001034
Bill Richardson5f2696d2014-09-23 22:03:56 -07001035 if (0 != futil_map_file(ifd, mapping, &buf, &buf_len)) {
Bill Richardson15dc6fc2014-09-02 14:45:44 -07001036 errorcnt++;
Bill Richardson5f2696d2014-09-23 22:03:56 -07001037 goto done;
1038 }
1039
1040 errorcnt += futil_traverse(buf, buf_len, &state, type);
1041
1042 errorcnt += futil_unmap_file(ifd, MAP_RW, buf, buf_len);
1043
1044done:
1045 if (ifd >= 0 && close(ifd)) {
1046 errorcnt++;
1047 fprintf(stderr, "Error when closing ifd: %s\n",
1048 strerror(errno));
Bill Richardson15dc6fc2014-09-02 14:45:44 -07001049 }
1050
1051 if (option.signprivate)
1052 free(option.signprivate);
1053 if (option.keyblock)
1054 free(option.keyblock);
1055 if (option.kernel_subkey)
1056 free(option.kernel_subkey);
1057
Bill Richardson5f2696d2014-09-23 22:03:56 -07001058 if (errorcnt)
1059 fprintf(stderr, "Use --help for usage instructions\n");
1060
Bill Richardson15dc6fc2014-09-02 14:45:44 -07001061 return !!errorcnt;
1062}
1063
Bill Richardson779796f2014-09-23 11:47:40 -07001064DECLARE_FUTIL_COMMAND(sign, do_sign,
Bill Richardson5f2696d2014-09-23 22:03:56 -07001065 "Sign / resign various binary components",
Bill Richardson779796f2014-09-23 11:47:40 -07001066 print_help);