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