6d448404a3b81625ad7c98581232dafd8d552cfa
[vboot.git] / futility / cmd_sign.c
1 /*
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 "file_type.h"
21 #include "file_type_bios.h"
22 #include "fmap.h"
23 #include "futility.h"
24 #include "futility_options.h"
25 #include "gbb_header.h"
26 #include "host_common.h"
27 #include "kernel_blob.h"
28 #include "util_misc.h"
29 #include "vb1_helper.h"
30 #include "vb2_struct.h"
31 #include "vb21_common.h"
32 #include "host_key2.h"
33 #include "vboot_common.h"
34
35 /* Options */
36 struct sign_option_s sign_option = {
37         .version = 1,
38         .arch = ARCH_UNSPECIFIED,
39         .kloadaddr = CROS_32BIT_ENTRY_ADDR,
40         .padding = 65536,
41         .type = FILE_TYPE_UNKNOWN,
42         .hash_alg = VB2_HASH_SHA256,            /* default */
43         .ro_size = 0xffffffff,
44         .rw_size = 0xffffffff,
45         .ro_offset = 0xffffffff,
46         .rw_offset = 0xffffffff,
47         .sig_size = 1024,
48 };
49
50 /* Helper to complain about invalid args. Returns num errors discovered */
51 static int no_opt_if(int expr, const char *optname)
52 {
53         if (expr) {
54                 fprintf(stderr, "Missing --%s option\n", optname);
55                 return 1;
56         }
57         return 0;
58 }
59
60 /* This wraps/signs a public key, producing a keyblock. */
61 int ft_sign_pubkey(const char *name, uint8_t *buf, uint32_t len, void *data)
62 {
63         VbPublicKey *data_key = (VbPublicKey *)buf;
64         VbKeyBlockHeader *vblock;
65
66         if (sign_option.pem_signpriv) {
67                 if (sign_option.pem_external) {
68                         /* External signing uses the PEM file directly. */
69                         vblock = KeyBlockCreate_external(
70                                 data_key,
71                                 sign_option.pem_signpriv,
72                                 sign_option.pem_algo, sign_option.flags,
73                                 sign_option.pem_external);
74                 } else {
75                         sign_option.signprivate = PrivateKeyReadPem(
76                                 sign_option.pem_signpriv,
77                                 sign_option.pem_algo);
78                         if (!sign_option.signprivate) {
79                                 fprintf(stderr,
80                                         "Unable to read PEM signing key: %s\n",
81                                         strerror(errno));
82                                 return 1;
83                         }
84                         sign_option.signprivate2 = vb2_read_private_key_pem(
85                                 sign_option.pem_signpriv,
86                                 sign_option.pem_algo);
87                         if (!sign_option.signprivate2) {
88                                 fprintf(stderr,
89                                         "Unable to read PEM signing key: %s\n",
90                                         strerror(errno));
91                                 return 1;
92                         }
93                         vblock = KeyBlockCreate(data_key,
94                                                 sign_option.signprivate,
95                                                 sign_option.flags);
96                 }
97         } else {
98                 /* Not PEM. Should already have a signing key. */
99                 vblock = KeyBlockCreate(data_key, sign_option.signprivate,
100                                         sign_option.flags);
101         }
102
103         /* Write it out */
104         return WriteSomeParts(sign_option.outfile,
105                               vblock, vblock->key_block_size,
106                               NULL, 0);
107 }
108
109 int ft_sign_raw_kernel(const char *name, uint8_t *buf, uint32_t len,
110                        void *data)
111 {
112         uint8_t *vmlinuz_data, *kblob_data, *vblock_data;
113         uint64_t vmlinuz_size, kblob_size, vblock_size;
114         int rv;
115
116         vmlinuz_data = buf;
117         vmlinuz_size = len;
118
119         kblob_data = CreateKernelBlob(
120                 vmlinuz_data, vmlinuz_size,
121                 sign_option.arch, sign_option.kloadaddr,
122                 sign_option.config_data, sign_option.config_size,
123                 sign_option.bootloader_data, sign_option.bootloader_size,
124                 &kblob_size);
125         if (!kblob_data) {
126                 fprintf(stderr, "Unable to create kernel blob\n");
127                 return 1;
128         }
129         Debug("kblob_size = 0x%" PRIx64 "\n", kblob_size);
130
131         vblock_data = SignKernelBlob(kblob_data, kblob_size,
132                                      sign_option.padding,
133                                      sign_option.version,
134                                      sign_option.kloadaddr,
135                                      sign_option.keyblock,
136                                      sign_option.signprivate,
137                                      sign_option.flags, &vblock_size);
138         if (!vblock_data) {
139                 fprintf(stderr, "Unable to sign kernel blob\n");
140                 free(kblob_data);
141                 return 1;
142         }
143         Debug("vblock_size = 0x%" PRIx64 "\n", vblock_size);
144
145         /* We should be creating a completely new output file.
146          * If not, something's wrong. */
147         if (!sign_option.create_new_outfile)
148                 DIE;
149
150         if (sign_option.vblockonly)
151                 rv = WriteSomeParts(sign_option.outfile,
152                                     vblock_data, vblock_size,
153                                     NULL, 0);
154         else
155                 rv = WriteSomeParts(sign_option.outfile,
156                                     vblock_data, vblock_size,
157                                     kblob_data, kblob_size);
158
159         free(vblock_data);
160         free(kblob_data);
161         return rv;
162 }
163
164 int ft_sign_kern_preamble(const char *name, uint8_t *buf, uint32_t len,
165                           void *data)
166 {
167         uint8_t *kpart_data, *kblob_data, *vblock_data;
168         uint64_t kpart_size, kblob_size, vblock_size;
169         VbKeyBlockHeader *keyblock = NULL;
170         VbKernelPreambleHeader *preamble = NULL;
171         int rv = 0;
172
173         kpart_data = buf;
174         kpart_size = len;
175
176         /* Note: This just sets some static pointers. It doesn't malloc. */
177         kblob_data = UnpackKPart(kpart_data, kpart_size, sign_option.padding,
178                                  &keyblock, &preamble, &kblob_size);
179
180         if (!kblob_data) {
181                 fprintf(stderr, "Unable to unpack kernel partition\n");
182                 return 1;
183         }
184
185         /*
186          * We don't let --kloadaddr change when resigning, because the original
187          * vbutil_kernel program didn't do it right. Since obviously no one
188          * ever noticed, we'll maintain bug-compatibility by just not allowing
189          * it here either. To enable it, we'd need to update the zeropage
190          * table's cmd_line_ptr as well as the preamble.
191          */
192         sign_option.kloadaddr = preamble->body_load_address;
193
194         /* Replace the config if asked */
195         if (sign_option.config_data &&
196             0 != UpdateKernelBlobConfig(kblob_data, kblob_size,
197                                         sign_option.config_data,
198                                         sign_option.config_size)) {
199                 fprintf(stderr, "Unable to update config\n");
200                 return 1;
201         }
202
203         /* Preserve the version unless a new one is given */
204         if (!sign_option.version_specified)
205                 sign_option.version = preamble->kernel_version;
206
207         /* Preserve the flags if not specified */
208         if (VbKernelHasFlags(preamble) == VBOOT_SUCCESS) {
209                 if (sign_option.flags_specified == 0)
210                         sign_option.flags = preamble->flags;
211         }
212
213         /* Replace the keyblock if asked */
214         if (sign_option.keyblock)
215                 keyblock = sign_option.keyblock;
216
217         /* Compute the new signature */
218         vblock_data = SignKernelBlob(kblob_data, kblob_size,
219                                      sign_option.padding,
220                                      sign_option.version,
221                                      sign_option.kloadaddr,
222                                      keyblock,
223                                      sign_option.signprivate,
224                                      sign_option.flags,
225                                      &vblock_size);
226         if (!vblock_data) {
227                 fprintf(stderr, "Unable to sign kernel blob\n");
228                 return 1;
229         }
230         Debug("vblock_size = 0x%" PRIx64 "\n", vblock_size);
231
232         if (sign_option.create_new_outfile) {
233                 /* Write out what we've been asked for */
234                 if (sign_option.vblockonly)
235                         rv = WriteSomeParts(sign_option.outfile,
236                                             vblock_data, vblock_size,
237                                             NULL, 0);
238                 else
239                         rv = WriteSomeParts(sign_option.outfile,
240                                             vblock_data, vblock_size,
241                                             kblob_data, kblob_size);
242         } else {
243                 /* If we're modifying an existing file, it's mmap'ed so that
244                  * all our modifications to the buffer will get flushed to
245                  * disk when we close it. */
246                 Memcpy(kpart_data, vblock_data, vblock_size);
247         }
248
249         free(vblock_data);
250         return rv;
251 }
252
253
254 int ft_sign_raw_firmware(const char *name, uint8_t *buf, uint32_t len,
255                          void *data)
256 {
257         struct vb2_signature *body_sig;
258         struct vb2_fw_preamble *preamble;
259         int rv;
260
261         body_sig = vb2_calculate_signature(buf, len, sign_option.signprivate2);
262         if (!body_sig) {
263                 fprintf(stderr, "Error calculating body signature\n");
264                 return 1;
265         }
266
267         preamble = vb2_create_fw_preamble(
268                         sign_option.version,
269                         (struct vb2_packed_key *)sign_option.kernel_subkey,
270                         body_sig,
271                         sign_option.signprivate2,
272                         sign_option.flags);
273         if (!preamble) {
274                 fprintf(stderr, "Error creating firmware preamble.\n");
275                 free(body_sig);
276                 return 1;
277         }
278
279         rv = WriteSomeParts(sign_option.outfile,
280                             sign_option.keyblock,
281                             sign_option.keyblock->key_block_size,
282                             preamble, preamble->preamble_size);
283
284         free(preamble);
285         free(body_sig);
286
287         return rv;
288 }
289
290 static const char usage_pubkey[] = "\n"
291         "To sign a public key / create a new keyblock:\n"
292         "\n"
293         "Required PARAMS:\n"
294         "  [--datapubkey]   INFILE          The public key to wrap\n"
295         "  [--outfile]      OUTFILE         The resulting keyblock\n"
296         "\n"
297         "Optional PARAMS:\n"
298         "  A private signing key, specified as either\n"
299         "    -s|--signprivate FILE.vbprivk  Signing key in .vbprivk format\n"
300         "  Or\n"
301         "    --pem_signpriv   FILE.pem      Signing key in PEM format...\n"
302         "    --pem_algo       NUM           AND the algorithm to use (0 - %d)\n"
303         "\n"
304         "  If a signing key is not given, the keyblock will not be signed."
305         "\n\n"
306         "And these, too:\n\n"
307         "  -f|--flags       NUM             Flags specifying use conditions\n"
308         "  --pem_external   PROGRAM"
309         "         External program to compute the signature\n"
310         "                                     (requires a PEM signing key)\n"
311         "\n";
312 static void print_help_pubkey(int argc, char *argv[])
313 {
314         printf(usage_pubkey, kNumAlgorithms - 1);
315 }
316
317
318 static const char usage_fw_main[] = "\n"
319         "To sign a raw firmware blob (FW_MAIN_A/B):\n"
320         "\n"
321         "Required PARAMS:\n"
322         "  -s|--signprivate FILE.vbprivk    The private firmware data key\n"
323         "  -b|--keyblock    FILE.keyblock   The keyblock containing the\n"
324         "                                     public firmware data key\n"
325         "  -k|--kernelkey   FILE.vbpubk     The public kernel subkey\n"
326         "  -v|--version     NUM             The firmware version number\n"
327         "  [--fv]           INFILE"
328         "          The raw firmware blob (FW_MAIN_A/B)\n"
329         "  [--outfile]      OUTFILE         Output VBLOCK_A/B\n"
330         "\n"
331         "Optional PARAMS:\n"
332         "  -f|--flags       NUM             The preamble flags value"
333         " (default is 0)\n"
334         "\n";
335 static void print_help_raw_firmware(int argc, char *argv[])
336 {
337         puts(usage_fw_main);
338 }
339
340 static const char usage_bios[] = "\n"
341         "To sign a complete firmware image (bios.bin):\n"
342         "\n"
343         "Required PARAMS:\n"
344         "  -s|--signprivate FILE.vbprivk    The private firmware data key\n"
345         "  -b|--keyblock    FILE.keyblock   The keyblock containing the\n"
346         "                                     public firmware data key\n"
347         "  -k|--kernelkey   FILE.vbpubk     The public kernel subkey\n"
348         "  [--infile]       INFILE          Input firmware image (modified\n"
349         "                                     in place if no OUTFILE given)\n"
350         "\n"
351         "These are required if the A and B firmware differ:\n"
352         "  -S|--devsign     FILE.vbprivk    The DEV private firmware data key\n"
353         "  -B|--devkeyblock FILE.keyblock   The keyblock containing the\n"
354         "                                     DEV public firmware data key\n"
355         "\n"
356         "Optional PARAMS:\n"
357         "  -v|--version     NUM             The firmware version number"
358         " (default %d)\n"
359         "  -f|--flags       NUM             The preamble flags value"
360         " (default is\n"
361         "                                     unchanged, or 0 if unknown)\n"
362         "  -d|--loemdir     DIR             Local OEM output vblock directory\n"
363         "  -l|--loemid      STRING          Local OEM vblock suffix\n"
364         "  [--outfile]      OUTFILE         Output firmware image\n"
365         "\n";
366 static void print_help_bios_image(int argc, char *argv[])
367 {
368         printf(usage_bios, sign_option.version);
369 }
370
371 static const char usage_new_kpart[] = "\n"
372         "To create a new kernel partition image (/dev/sda2, /dev/mmcblk0p2):\n"
373         "\n"
374         "Required PARAMS:\n"
375         "  -s|--signprivate FILE.vbprivk"
376         "    The private key to sign the kernel blob\n"
377         "  -b|--keyblock    FILE.keyblock   Keyblock containing the public\n"
378         "                                     key to verify the kernel blob\n"
379         "  -v|--version     NUM             The kernel version number\n"
380         "  --bootloader     FILE            Bootloader stub\n"
381         "  --config         FILE            The kernel commandline file\n"
382         "  --arch           ARCH            The CPU architecture (one of\n"
383         "                                     x86|amd64, arm|aarch64, mips)\n"
384         "  [--vmlinuz]      INFILE          Linux kernel bzImage file\n"
385         "  [--outfile]      OUTFILE         Output kernel partition or vblock\n"
386         "\n"
387         "Optional PARAMS:\n"
388         "  --kloadaddr      NUM"
389         "             RAM address to load the kernel body\n"
390         "                                     (default 0x%x)\n"
391         "  --pad            NUM             The vblock padding size in bytes\n"
392         "                                     (default 0x%x)\n"
393         " --vblockonly                      Emit just the vblock (requires a\n"
394         "                                     distinct outfile)\n"
395         "  -f|--flags       NUM             The preamble flags value\n"
396         "\n";
397 static void print_help_raw_kernel(int argc, char *argv[])
398 {
399         printf(usage_new_kpart, sign_option.kloadaddr, sign_option.padding);
400 }
401
402 static const char usage_old_kpart[] = "\n"
403         "To resign an existing kernel partition (/dev/sda2, /dev/mmcblk0p2):\n"
404         "\n"
405         "Required PARAMS:\n"
406         "  -s|--signprivate FILE.vbprivk"
407         "    The private key to sign the kernel blob\n"
408         "  [--infile]       INFILE          Input kernel partition (modified\n"
409         "                                     in place if no OUTFILE given)\n"
410         "\n"
411         "Optional PARAMS:\n"
412         "  -b|--keyblock    FILE.keyblock   Keyblock containing the public\n"
413         "                                     key to verify the kernel blob\n"
414         "  -v|--version     NUM             The kernel version number\n"
415         "  --config         FILE            The kernel commandline file\n"
416         "  --pad            NUM             The vblock padding size in bytes\n"
417         "                                     (default 0x%x)\n"
418         "  [--outfile]      OUTFILE         Output kernel partition or vblock\n"
419         "  --vblockonly                     Emit just the vblock (requires a\n"
420         "                                     distinct OUTFILE)\n"
421         "  -f|--flags       NUM             The preamble flags value\n"
422         "\n";
423 static void print_help_kern_preamble(int argc, char *argv[])
424 {
425         printf(usage_old_kpart, sign_option.padding);
426 }
427
428 static void print_help_usbpd1(int argc, char *argv[])
429 {
430         struct vb2_text_vs_enum *entry;
431
432         printf("\n"
433                "Usage:  " MYNAME " %s --type %s [options] INFILE [OUTFILE]\n"
434                "\n"
435                "This signs a %s.\n"
436                "\n"
437                "The INFILE is assumed to consist of equal-sized RO and RW"
438                " sections,\n"
439                "with the public key at the end of of the RO section and the"
440                " signature\n"
441                "at the end of the RW section (both in an opaque binary"
442                " format).\n"
443                "Signing the image will update both binary blobs, so both"
444                " public and\n"
445                "private keys are required.\n"
446                "\n"
447                "The signing key is specified with:\n"
448                "\n"
449                "  --pem            "
450                "FILE          Signing keypair in PEM format\n"
451                "\n"
452                "  --hash_alg       "
453                "NUM           Hash algorithm to use:\n",
454                argv[0],
455                futil_file_type_name(FILE_TYPE_USBPD1),
456                futil_file_type_desc(FILE_TYPE_USBPD1));
457         for (entry = vb2_text_vs_hash; entry->name; entry++)
458                 printf("                                   %d / %s%s\n",
459                        entry->num, entry->name,
460                        entry->num == VB2_HASH_SHA256 ? " (default)" : "");
461         printf("\n"
462                "The size and offset assumptions can be overridden. "
463                "All numbers are in bytes.\n"
464                "Specify a size of 0 to ignore that section.\n"
465                "\n"
466                "  --ro_size        NUM"
467                "           Size of the RO section (default half)\n"
468                "  --rw_size        NUM"
469                "           Size of the RW section (default half)\n"
470                "  --ro_offset      NUM"
471                "           Start of the RO section (default 0)\n"
472                "  --rw_offset      NUM"
473                "           Start of the RW section (default half)\n"
474                "\n");
475 }
476
477 static void print_help_rwsig(int argc, char *argv[])
478 {
479         printf("\n"
480                "Usage:  " MYNAME " %s --type %s [options] INFILE [OUTFILE]\n"
481                "\n"
482                "This signs a %s.\n"
483                "\n"
484                "The INFILE is a binary blob of arbitrary size."
485                " It is signed using the\n"
486                "private key and the vb21_signature blob emitted.\n"
487                "\n"
488                "If no OUTFILE is specified, the INFILE should contain"
489                " an existing\n"
490                "vb21_signature blob near its end. The data_size from that"
491                " signature is\n"
492                "used to re-sign a portion of the INFILE, and the old"
493                " signature blob is\n"
494                "replaced.\n"
495                "\n"
496                "Options:\n"
497                "\n"
498                "  --prikey      FILE.vbprik2      "
499                "Private key in vb2 format (required)\n"
500                "  --sig_size    NUM               "
501                "Offset from the end of INFILE where the\n"
502                "                                    "
503                "signature blob should be located\n"
504                "                                    "
505                "(default 1024 bytes)\n"
506                "  --data_size   NUM               "
507                "Number of bytes of INFILE to sign\n"
508                "\n",
509                argv[0],
510                futil_file_type_name(FILE_TYPE_RWSIG),
511                futil_file_type_desc(FILE_TYPE_RWSIG));
512 }
513
514 static void (*help_type[NUM_FILE_TYPES])(int argc, char *argv[]) = {
515         [FILE_TYPE_PUBKEY] = &print_help_pubkey,
516         [FILE_TYPE_RAW_FIRMWARE] = &print_help_raw_firmware,
517         [FILE_TYPE_BIOS_IMAGE] = &print_help_bios_image,
518         [FILE_TYPE_RAW_KERNEL] = &print_help_raw_kernel,
519         [FILE_TYPE_KERN_PREAMBLE] = &print_help_kern_preamble,
520         [FILE_TYPE_USBPD1] = &print_help_usbpd1,
521         [FILE_TYPE_RWSIG] = &print_help_rwsig,
522 };
523
524 static const char usage_default[] = "\n"
525         "Usage:  " MYNAME " %s [PARAMS] INFILE [OUTFILE]\n"
526         "\n"
527         "The following signing operations are supported:\n"
528         "\n"
529         "    INFILE                              OUTFILE\n"
530         "  public key (.vbpubk)                keyblock\n"
531         "  raw firmware blob (FW_MAIN_A/B)     firmware preamble (VBLOCK_A/B)\n"
532         "  full firmware image (bios.bin)      same, or signed in-place\n"
533         "  raw linux kernel (vmlinuz)          kernel partition image\n"
534         "  kernel partition (/dev/sda2)        same, or signed in-place\n"
535         "  usbpd1 firmware image               same, or signed in-place\n"
536         "  RW device image                     same, or signed in-place\n"
537         "\n"
538         "For more information, use \"" MYNAME " help %s TYPE\", where\n"
539         "TYPE is one of:\n\n";
540 static void print_help_default(int argc, char *argv[])
541 {
542         enum futil_file_type type;
543
544         printf(usage_default, argv[0], argv[0]);
545         for (type = 0; type < NUM_FILE_TYPES; type++)
546                 if (help_type[type])
547                         printf("  %s", futil_file_type_name(type));
548         printf("\n\n");
549 }
550
551 static void print_help(int argc, char *argv[])
552 {
553         enum futil_file_type type = FILE_TYPE_UNKNOWN;
554
555         if (argc > 1)
556                 futil_str_to_file_type(argv[1], &type);
557
558         if (help_type[type])
559                 help_type[type](argc, argv);
560         else
561                 print_help_default(argc, argv);
562 }
563
564 enum no_short_opts {
565         OPT_FV = 1000,
566         OPT_INFILE,
567         OPT_OUTFILE,
568         OPT_BOOTLOADER,
569         OPT_CONFIG,
570         OPT_ARCH,
571         OPT_KLOADADDR,
572         OPT_PADDING,
573         OPT_PEM_SIGNPRIV,
574         OPT_PEM_ALGO,
575         OPT_PEM_EXTERNAL,
576         OPT_TYPE,
577         OPT_HASH_ALG,
578         OPT_RO_SIZE,
579         OPT_RW_SIZE,
580         OPT_RO_OFFSET,
581         OPT_RW_OFFSET,
582         OPT_DATA_SIZE,
583         OPT_SIG_SIZE,
584         OPT_PRIKEY,
585         OPT_HELP,
586 };
587
588 static const struct option long_opts[] = {
589         /* name    hasarg *flag  val */
590         {"signprivate",  1, NULL, 's'},
591         {"keyblock",     1, NULL, 'b'},
592         {"kernelkey",    1, NULL, 'k'},
593         {"devsign",      1, NULL, 'S'},
594         {"devkeyblock",  1, NULL, 'B'},
595         {"version",      1, NULL, 'v'},
596         {"flags",        1, NULL, 'f'},
597         {"loemdir",      1, NULL, 'd'},
598         {"loemid",       1, NULL, 'l'},
599         {"fv",           1, NULL, OPT_FV},
600         {"infile",       1, NULL, OPT_INFILE},
601         {"datapubkey",   1, NULL, OPT_INFILE},  /* alias */
602         {"vmlinuz",      1, NULL, OPT_INFILE},  /* alias */
603         {"outfile",      1, NULL, OPT_OUTFILE},
604         {"bootloader",   1, NULL, OPT_BOOTLOADER},
605         {"config",       1, NULL, OPT_CONFIG},
606         {"arch",         1, NULL, OPT_ARCH},
607         {"kloadaddr",    1, NULL, OPT_KLOADADDR},
608         {"pad",          1, NULL, OPT_PADDING},
609         {"pem_signpriv", 1, NULL, OPT_PEM_SIGNPRIV},
610         {"pem",          1, NULL, OPT_PEM_SIGNPRIV}, /* alias */
611         {"pem_algo",     1, NULL, OPT_PEM_ALGO},
612         {"pem_external", 1, NULL, OPT_PEM_EXTERNAL},
613         {"type",         1, NULL, OPT_TYPE},
614         {"vblockonly",   0, &sign_option.vblockonly, 1},
615         {"hash_alg",     1, NULL, OPT_HASH_ALG},
616         {"ro_size",      1, NULL, OPT_RO_SIZE},
617         {"rw_size",      1, NULL, OPT_RW_SIZE},
618         {"ro_offset",    1, NULL, OPT_RO_OFFSET},
619         {"rw_offset",    1, NULL, OPT_RW_OFFSET},
620         {"data_size",    1, NULL, OPT_DATA_SIZE},
621         {"sig_size",     1, NULL, OPT_SIG_SIZE},
622         {"prikey",       1, NULL, OPT_PRIKEY},
623         {"privkey",      1, NULL, OPT_PRIKEY},  /* alias */
624         {"help",         0, NULL, OPT_HELP},
625         {NULL,           0, NULL, 0},
626 };
627 static char *short_opts = ":s:b:k:S:B:v:f:d:l:";
628
629 /* Return zero on success */
630 static int parse_number_opt(const char *arg, const char *name, uint32_t *dest)
631 {
632         char *e;
633         uint32_t val = strtoul(arg, &e, 0);
634         if (!*arg || (e && *e)) {
635                 fprintf(stderr, "Invalid --%s \"%s\"\n", name, arg);
636                 return 1;
637         }
638         *dest = val;
639         return 0;
640 }
641
642 static int do_sign(int argc, char *argv[])
643 {
644         char *infile = 0;
645         int i;
646         int ifd = -1;
647         int errorcnt = 0;
648         uint8_t *buf;
649         uint32_t buf_len;
650         char *e = 0;
651         int mapping;
652         int helpind = 0;
653         int longindex;
654
655         opterr = 0;             /* quiet, you */
656         while ((i = getopt_long(argc, argv, short_opts, long_opts,
657                                 &longindex)) != -1) {
658                 switch (i) {
659                 case 's':
660                         sign_option.signprivate = PrivateKeyRead(optarg);
661                         if (!sign_option.signprivate) {
662                                 fprintf(stderr, "Error reading %s\n", optarg);
663                                 errorcnt++;
664                         }
665                         sign_option.signprivate2 = vb2_read_private_key(optarg);
666                         if (!sign_option.signprivate2) {
667                                 fprintf(stderr, "Error reading %s\n", optarg);
668                                 errorcnt++;
669                         }
670                         break;
671                 case 'b':
672                         sign_option.keyblock = KeyBlockRead(optarg);
673                         if (!sign_option.keyblock) {
674                                 fprintf(stderr, "Error reading %s\n", optarg);
675                                 errorcnt++;
676                         }
677                         break;
678                 case 'k':
679                         sign_option.kernel_subkey = PublicKeyRead(optarg);
680                         if (!sign_option.kernel_subkey) {
681                                 fprintf(stderr, "Error reading %s\n", optarg);
682                                 errorcnt++;
683                         }
684                         break;
685                 case 'S':
686                         sign_option.devsignprivate =
687                                 vb2_read_private_key(optarg);
688                         if (!sign_option.devsignprivate) {
689                                 fprintf(stderr, "Error reading %s\n", optarg);
690                                 errorcnt++;
691                         }
692                         break;
693                 case 'B':
694                         sign_option.devkeyblock = KeyBlockRead(optarg);
695                         if (!sign_option.devkeyblock) {
696                                 fprintf(stderr, "Error reading %s\n", optarg);
697                                 errorcnt++;
698                         }
699                         break;
700                 case 'v':
701                         sign_option.version_specified = 1;
702                         sign_option.version = strtoul(optarg, &e, 0);
703                         if (!*optarg || (e && *e)) {
704                                 fprintf(stderr,
705                                         "Invalid --version \"%s\"\n", optarg);
706                                 errorcnt++;
707                         }
708                         break;
709
710                 case 'f':
711                         sign_option.flags_specified = 1;
712                         errorcnt += parse_number_opt(optarg, "flags",
713                                                      &sign_option.flags);
714                         break;
715                 case 'd':
716                         sign_option.loemdir = optarg;
717                         break;
718                 case 'l':
719                         sign_option.loemid = optarg;
720                         break;
721                 case OPT_FV:
722                         sign_option.fv_specified = 1;
723                         /* fallthrough */
724                 case OPT_INFILE:
725                         sign_option.inout_file_count++;
726                         infile = optarg;
727                         break;
728                 case OPT_OUTFILE:
729                         sign_option.inout_file_count++;
730                         sign_option.outfile = optarg;
731                         break;
732                 case OPT_BOOTLOADER:
733                         sign_option.bootloader_data = ReadFile(
734                                 optarg, &sign_option.bootloader_size);
735                         if (!sign_option.bootloader_data) {
736                                 fprintf(stderr,
737                                         "Error reading bootloader file: %s\n",
738                                         strerror(errno));
739                                 errorcnt++;
740                         }
741                         Debug("bootloader file size=0x%" PRIx64 "\n",
742                               sign_option.bootloader_size);
743                         break;
744                 case OPT_CONFIG:
745                         sign_option.config_data = ReadConfigFile(
746                                 optarg, &sign_option.config_size);
747                         if (!sign_option.config_data) {
748                                 fprintf(stderr,
749                                         "Error reading config file: %s\n",
750                                         strerror(errno));
751                                 errorcnt++;
752                         }
753                         break;
754                 case OPT_ARCH:
755                         /* check the first 3 characters to also match x86_64 */
756                         if ((!strncasecmp(optarg, "x86", 3)) ||
757                             (!strcasecmp(optarg, "amd64")))
758                                 sign_option.arch = ARCH_X86;
759                         else if ((!strcasecmp(optarg, "arm")) ||
760                                  (!strcasecmp(optarg, "aarch64")))
761                                 sign_option.arch = ARCH_ARM;
762                         else if (!strcasecmp(optarg, "mips"))
763                                 sign_option.arch = ARCH_MIPS;
764                         else {
765                                 fprintf(stderr,
766                                         "Unknown architecture: \"%s\"\n",
767                                         optarg);
768                                 errorcnt++;
769                         }
770                         break;
771                 case OPT_KLOADADDR:
772                         errorcnt += parse_number_opt(optarg, "kloadaddr",
773                                                      &sign_option.kloadaddr);
774                         break;
775                 case OPT_PADDING:
776                         errorcnt += parse_number_opt(optarg, "padding",
777                                                      &sign_option.padding);
778                         break;
779                 case OPT_RO_SIZE:
780                         errorcnt += parse_number_opt(optarg, "ro_size",
781                                                      &sign_option.ro_size);
782                         break;
783                 case OPT_RW_SIZE:
784                         errorcnt += parse_number_opt(optarg, "rw_size",
785                                                      &sign_option.rw_size);
786                         break;
787                 case OPT_RO_OFFSET:
788                         errorcnt += parse_number_opt(optarg, "ro_offset",
789                                                      &sign_option.ro_offset);
790                         break;
791                 case OPT_RW_OFFSET:
792                         errorcnt += parse_number_opt(optarg, "rw_offset",
793                                                      &sign_option.rw_offset);
794                         break;
795                 case OPT_DATA_SIZE:
796                         errorcnt += parse_number_opt(optarg, "data_size",
797                                                      &sign_option.data_size);
798                         break;
799                 case OPT_SIG_SIZE:
800                         errorcnt += parse_number_opt(optarg, "sig_size",
801                                                      &sign_option.sig_size);
802                         break;
803                 case OPT_PEM_SIGNPRIV:
804                         sign_option.pem_signpriv = optarg;
805                         break;
806                 case OPT_PEM_ALGO:
807                         sign_option.pem_algo_specified = 1;
808                         sign_option.pem_algo = strtoul(optarg, &e, 0);
809                         if (!*optarg || (e && *e) ||
810                             (sign_option.pem_algo >= kNumAlgorithms)) {
811                                 fprintf(stderr,
812                                         "Invalid --pem_algo \"%s\"\n", optarg);
813                                 errorcnt++;
814                         }
815                         break;
816                 case OPT_HASH_ALG:
817                         if (!vb2_lookup_hash_alg(optarg,
818                                                  &sign_option.hash_alg)) {
819                                 fprintf(stderr,
820                                         "invalid hash_alg \"%s\"\n", optarg);
821                                 errorcnt++;
822                         }
823                         break;
824                 case OPT_PEM_EXTERNAL:
825                         sign_option.pem_external = optarg;
826                         break;
827                 case OPT_TYPE:
828                         if (!futil_str_to_file_type(optarg,
829                                                     &sign_option.type)) {
830                                 if (!strcasecmp("help", optarg))
831                                     print_file_types_and_exit(errorcnt);
832                                 fprintf(stderr,
833                                         "Invalid --type \"%s\"\n", optarg);
834                                 errorcnt++;
835                         }
836                         break;
837                 case OPT_PRIKEY:
838                         if (vb21_private_key_read(&sign_option.prikey,
839                                                   optarg)) {
840                                 fprintf(stderr, "Error reading %s\n", optarg);
841                                 errorcnt++;
842                         }
843                         break;
844                 case OPT_HELP:
845                         helpind = optind - 1;
846                         break;
847
848                 case '?':
849                         if (optopt)
850                                 fprintf(stderr, "Unrecognized option: -%c\n",
851                                         optopt);
852                         else
853                                 fprintf(stderr, "Unrecognized option: %s\n",
854                                         argv[optind - 1]);
855                         errorcnt++;
856                         break;
857                 case ':':
858                         fprintf(stderr, "Missing argument to -%c\n", optopt);
859                         errorcnt++;
860                         break;
861                 case 0:                         /* handled option */
862                         break;
863                 default:
864                         Debug("i=%d\n", i);
865                         DIE;
866                 }
867         }
868
869         if (helpind) {
870                 /* Skip all the options we've already parsed */
871                 optind--;
872                 argv[optind] = argv[0];
873                 argc -= optind;
874                 argv += optind;
875                 print_help(argc, argv);
876                 return !!errorcnt;
877         }
878
879         /* If we don't have an input file already, we need one */
880         if (!infile) {
881                 if (argc - optind <= 0) {
882                         errorcnt++;
883                         fprintf(stderr, "ERROR: missing input filename\n");
884                         goto done;
885                 } else {
886                         sign_option.inout_file_count++;
887                         infile = argv[optind++];
888                 }
889         }
890
891         /* Look for an output file if we don't have one, just in case. */
892         if (!sign_option.outfile && argc - optind > 0) {
893                 sign_option.inout_file_count++;
894                 sign_option.outfile = argv[optind++];
895         }
896
897         /* What are we looking at? */
898         if (sign_option.type == FILE_TYPE_UNKNOWN &&
899             futil_file_type(infile, &sign_option.type)) {
900                 errorcnt++;
901                 goto done;
902         }
903
904         /* We may be able to infer the type based on the other args */
905         if (sign_option.type == FILE_TYPE_UNKNOWN) {
906                 if (sign_option.bootloader_data || sign_option.config_data
907                     || sign_option.arch != ARCH_UNSPECIFIED)
908                         sign_option.type = FILE_TYPE_RAW_KERNEL;
909                 else if (sign_option.kernel_subkey || sign_option.fv_specified)
910                         sign_option.type = FILE_TYPE_RAW_FIRMWARE;
911         }
912
913         Debug("type=%s\n", futil_file_type_name(sign_option.type));
914
915         /* Check the arguments for the type of thing we want to sign */
916         switch (sign_option.type) {
917         case FILE_TYPE_PUBKEY:
918                 sign_option.create_new_outfile = 1;
919                 if (sign_option.signprivate && sign_option.pem_signpriv) {
920                         fprintf(stderr,
921                                 "Only one of --signprivate and --pem_signpriv"
922                                 " can be specified\n");
923                         errorcnt++;
924                 }
925                 if ((sign_option.signprivate &&
926                      sign_option.pem_algo_specified) ||
927                     (sign_option.pem_signpriv &&
928                      !sign_option.pem_algo_specified)) {
929                         fprintf(stderr, "--pem_algo must be used with"
930                                 " --pem_signpriv\n");
931                         errorcnt++;
932                 }
933                 if (sign_option.pem_external && !sign_option.pem_signpriv) {
934                         fprintf(stderr, "--pem_external must be used with"
935                                 " --pem_signpriv\n");
936                         errorcnt++;
937                 }
938                 /* We'll wait to read the PEM file, since the external signer
939                  * may want to read it instead. */
940                 break;
941         case FILE_TYPE_BIOS_IMAGE:
942         case FILE_TYPE_OLD_BIOS_IMAGE:
943                 errorcnt += no_opt_if(!sign_option.signprivate, "signprivate");
944                 errorcnt += no_opt_if(!sign_option.keyblock, "keyblock");
945                 errorcnt += no_opt_if(!sign_option.kernel_subkey, "kernelkey");
946                 break;
947         case FILE_TYPE_KERN_PREAMBLE:
948                 errorcnt += no_opt_if(!sign_option.signprivate, "signprivate");
949                 if (sign_option.vblockonly || sign_option.inout_file_count > 1)
950                         sign_option.create_new_outfile = 1;
951                 break;
952         case FILE_TYPE_RAW_FIRMWARE:
953                 sign_option.create_new_outfile = 1;
954                 errorcnt += no_opt_if(!sign_option.signprivate, "signprivate");
955                 errorcnt += no_opt_if(!sign_option.keyblock, "keyblock");
956                 errorcnt += no_opt_if(!sign_option.kernel_subkey, "kernelkey");
957                 errorcnt += no_opt_if(!sign_option.version_specified,
958                                       "version");
959                 break;
960         case FILE_TYPE_RAW_KERNEL:
961                 sign_option.create_new_outfile = 1;
962                 errorcnt += no_opt_if(!sign_option.signprivate, "signprivate");
963                 errorcnt += no_opt_if(!sign_option.keyblock, "keyblock");
964                 errorcnt += no_opt_if(!sign_option.version_specified,
965                                       "version");
966                 errorcnt += no_opt_if(!sign_option.bootloader_data,
967                                       "bootloader");
968                 errorcnt += no_opt_if(!sign_option.config_data, "config");
969                 errorcnt += no_opt_if(sign_option.arch == ARCH_UNSPECIFIED,
970                                       "arch");
971                 break;
972         case FILE_TYPE_USBPD1:
973                 errorcnt += no_opt_if(!sign_option.pem_signpriv, "pem");
974                 errorcnt += no_opt_if(sign_option.hash_alg == VB2_HASH_INVALID,
975                                       "hash_alg");
976                 break;
977         case FILE_TYPE_RWSIG:
978                 errorcnt += no_opt_if(!sign_option.prikey, "prikey");
979                 break;
980         default:
981                 /* Anything else we don't care */
982                 break;
983         }
984
985         Debug("infile=%s\n", infile);
986         Debug("sign_option.inout_file_count=%d\n", sign_option.inout_file_count);
987         Debug("sign_option.create_new_outfile=%d\n",
988               sign_option.create_new_outfile);
989
990         /* Make sure we have an output file if one is needed */
991         if (!sign_option.outfile) {
992                 if (sign_option.create_new_outfile) {
993                         errorcnt++;
994                         fprintf(stderr, "Missing output filename\n");
995                         goto done;
996                 } else {
997                         sign_option.outfile = infile;
998                 }
999         }
1000
1001         Debug("sign_option.outfile=%s\n", sign_option.outfile);
1002
1003         if (argc - optind > 0) {
1004                 errorcnt++;
1005                 fprintf(stderr, "ERROR: too many arguments left over\n");
1006         }
1007
1008         if (errorcnt)
1009                 goto done;
1010
1011         if (sign_option.create_new_outfile) {
1012                 /* The input is read-only, the output is write-only. */
1013                 mapping = MAP_RO;
1014                 Debug("open RO %s\n", infile);
1015                 ifd = open(infile, O_RDONLY);
1016                 if (ifd < 0) {
1017                         errorcnt++;
1018                         fprintf(stderr, "Can't open %s for reading: %s\n",
1019                                 infile, strerror(errno));
1020                         goto done;
1021                 }
1022         } else {
1023                 /* We'll read-modify-write the output file */
1024                mapping = MAP_RW;
1025                if (sign_option.inout_file_count > 1)
1026                        futil_copy_file_or_die(infile, sign_option.outfile);
1027                Debug("open RW %s\n", sign_option.outfile);
1028                infile = sign_option.outfile;
1029                ifd = open(sign_option.outfile, O_RDWR);
1030                if (ifd < 0) {
1031                        errorcnt++;
1032                        fprintf(stderr, "Can't open %s for writing: %s\n",
1033                                sign_option.outfile, strerror(errno));
1034                        goto done;
1035                }
1036         }
1037
1038         if (0 != futil_map_file(ifd, mapping, &buf, &buf_len)) {
1039                 errorcnt++;
1040                 goto done;
1041         }
1042
1043         errorcnt += futil_file_type_sign(sign_option.type, infile,
1044                                          buf, buf_len);
1045
1046         errorcnt += futil_unmap_file(ifd, mapping, buf, buf_len);
1047
1048 done:
1049         if (ifd >= 0 && close(ifd)) {
1050                 errorcnt++;
1051                 fprintf(stderr, "Error when closing ifd: %s\n",
1052                         strerror(errno));
1053         }
1054
1055         if (sign_option.signprivate)
1056                 free(sign_option.signprivate);
1057         if (sign_option.signprivate2)
1058                 free(sign_option.signprivate2);
1059         if (sign_option.keyblock)
1060                 free(sign_option.keyblock);
1061         if (sign_option.kernel_subkey)
1062                 free(sign_option.kernel_subkey);
1063
1064         if (errorcnt)
1065                 fprintf(stderr, "Use --help for usage instructions\n");
1066
1067         return !!errorcnt;
1068 }
1069
1070 DECLARE_FUTIL_COMMAND(sign, do_sign, VBOOT_VERSION_ALL,
1071                       "Sign / resign various binary components");