futility: Use only vboot 2.0 APIs for keyblocks
[vboot.git] / futility / cmd_vbutil_kernel.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  * Verified boot kernel utility
7  */
8
9 #include <errno.h>
10 #include <fcntl.h>
11 #include <getopt.h>
12 #include <inttypes.h>           /* For PRIu64 */
13 #ifndef HAVE_MACOS
14 #include <linux/fs.h>           /* For BLKGETSIZE64 */
15 #endif
16 #include <stdarg.h>
17 #include <stdio.h>
18 #include <string.h>
19 #include <sys/ioctl.h>
20 #include <sys/stat.h>
21 #include <unistd.h>
22
23 #include "file_type.h"
24 #include "futility.h"
25 #include "host_common.h"
26 #include "kernel_blob.h"
27 #include "vb1_helper.h"
28 #include "vb2_struct.h"
29
30 static void Fatal(const char *format, ...)
31 {
32         va_list ap;
33         va_start(ap, format);
34         fprintf(stderr, "ERROR: ");
35         vfprintf(stderr, format, ap);
36         va_end(ap);
37         exit(1);
38 }
39
40 /* Global opts */
41 static int opt_verbose;
42 static int opt_vblockonly;
43 static uint64_t opt_pad = 65536;
44
45 /* Command line options */
46 enum {
47         OPT_MODE_PACK = 1000,
48         OPT_MODE_REPACK,
49         OPT_MODE_VERIFY,
50         OPT_MODE_GET_VMLINUZ,
51         OPT_ARCH,
52         OPT_OLDBLOB,
53         OPT_KLOADADDR,
54         OPT_KEYBLOCK,
55         OPT_SIGNPUBKEY,
56         OPT_SIGNPRIVATE,
57         OPT_VERSION,
58         OPT_VMLINUZ,
59         OPT_BOOTLOADER,
60         OPT_CONFIG,
61         OPT_VBLOCKONLY,
62         OPT_PAD,
63         OPT_VERBOSE,
64         OPT_MINVERSION,
65         OPT_VMLINUZ_OUT,
66         OPT_FLAGS,
67         OPT_HELP,
68 };
69
70 static const struct option long_opts[] = {
71         {"pack", 1, 0, OPT_MODE_PACK},
72         {"repack", 1, 0, OPT_MODE_REPACK},
73         {"verify", 1, 0, OPT_MODE_VERIFY},
74         {"get-vmlinuz", 1, 0, OPT_MODE_GET_VMLINUZ},
75         {"arch", 1, 0, OPT_ARCH},
76         {"oldblob", 1, 0, OPT_OLDBLOB},
77         {"kloadaddr", 1, 0, OPT_KLOADADDR},
78         {"keyblock", 1, 0, OPT_KEYBLOCK},
79         {"signpubkey", 1, 0, OPT_SIGNPUBKEY},
80         {"signprivate", 1, 0, OPT_SIGNPRIVATE},
81         {"version", 1, 0, OPT_VERSION},
82         {"minversion", 1, 0, OPT_MINVERSION},
83         {"vmlinuz", 1, 0, OPT_VMLINUZ},
84         {"bootloader", 1, 0, OPT_BOOTLOADER},
85         {"config", 1, 0, OPT_CONFIG},
86         {"vblockonly", 0, 0, OPT_VBLOCKONLY},
87         {"pad", 1, 0, OPT_PAD},
88         {"verbose", 0, &opt_verbose, 1},
89         {"vmlinuz-out", 1, 0, OPT_VMLINUZ_OUT},
90         {"flags", 1, 0, OPT_FLAGS},
91         {"help", 0, 0, OPT_HELP},
92         {NULL, 0, 0, 0}
93 };
94
95
96
97 static const char usage[] =
98         "\n"
99         "Usage:  " MYNAME " %s --pack <file> [PARAMETERS]\n"
100         "\n"
101         "  Required parameters:\n"
102         "    --keyblock <file>         Key block in .keyblock format\n"
103         "    --signprivate <file>      Private key to sign kernel data,\n"
104         "                                in .vbprivk format\n"
105         "    --version <number>        Kernel version\n"
106         "    --vmlinuz <file>          Linux kernel bzImage file\n"
107         "    --bootloader <file>       Bootloader stub\n"
108         "    --config <file>           Command line file\n"
109         "    --arch <arch>             Cpu architecture (default x86)\n"
110         "\n"
111         "  Optional:\n"
112         "    --kloadaddr <address>     Assign kernel body load address\n"
113         "    --pad <number>            Verification padding size in bytes\n"
114         "    --vblockonly              Emit just the verification blob\n"
115         "    --flags NUM               Flags to be passed in the header\n"
116         "\nOR\n\n"
117         "Usage:  " MYNAME " %s --repack <file> [PARAMETERS]\n"
118         "\n"
119         "  Required parameters:\n"
120         "    --signprivate <file>      Private key to sign kernel data,\n"
121         "                                in .vbprivk format\n"
122         "    --oldblob <file>          Previously packed kernel blob\n"
123         "                                (including verfication blob)\n"
124         "\n"
125         "  Optional:\n"
126         "    --keyblock <file>         Key block in .keyblock format\n"
127         "    --config <file>           New command line file\n"
128         "    --version <number>        Kernel version\n"
129         "    --kloadaddr <address>     Assign kernel body load address\n"
130         "    --pad <number>            Verification blob size in bytes\n"
131         "    --vblockonly              Emit just the verification blob\n"
132         "\nOR\n\n"
133         "Usage:  " MYNAME " %s --verify <file> [PARAMETERS]\n"
134         "\n"
135         "  Optional:\n"
136         "    --signpubkey <file>"
137         "       Public key to verify kernel keyblock,\n"
138         "                                in .vbpubk format\n"
139         "    --verbose                 Print a more detailed report\n"
140         "    --keyblock <file>         Outputs the verified key block,\n"
141         "                                in .keyblock format\n"
142         "    --pad <number>            Verification padding size in bytes\n"
143         "    --minversion <number>     Minimum combined kernel key version\n"
144         "\nOR\n\n"
145         "Usage:  " MYNAME " %s --get-vmlinuz <file> [PARAMETERS]\n"
146         "\n"
147         "  Required parameters:\n"
148         "    --vmlinuz-out <file>      vmlinuz image output file\n"
149         "\n";
150
151
152 /* Print help and return error */
153 static void print_help(int argc, char *argv[])
154 {
155         printf(usage, argv[0], argv[0], argv[0], argv[0]);
156 }
157
158
159 /* Return an explanation when fread() fails. */
160 static const char *error_fread(FILE *fp)
161 {
162         const char *retval = "beats me why";
163         if (feof(fp))
164                 retval = "EOF";
165         else if (ferror(fp))
166                 retval = strerror(errno);
167         clearerr(fp);
168         return retval;
169 }
170
171
172 /* This reads a complete kernel partition into a buffer */
173 static uint8_t *ReadOldKPartFromFileOrDie(const char *filename,
174                                          uint64_t *size_ptr)
175 {
176         FILE *fp = NULL;
177         struct stat statbuf;
178         uint8_t *buf;
179         uint64_t file_size = 0;
180
181         if (0 != stat(filename, &statbuf))
182                 Fatal("Unable to stat %s: %s\n", filename, strerror(errno));
183
184         if (S_ISBLK(statbuf.st_mode)) {
185 #ifndef HAVE_MACOS
186                 int fd = open(filename, O_RDONLY);
187                 if (fd >= 0) {
188                         ioctl(fd, BLKGETSIZE64, &file_size);
189                         close(fd);
190                 }
191 #endif
192         } else {
193                 file_size = statbuf.st_size;
194         }
195         Debug("%s size is 0x%" PRIx64 "\n", filename, file_size);
196         if (file_size < opt_pad)
197                 Fatal("%s is too small to be a valid kernel blob\n");
198
199         Debug("Reading %s\n", filename);
200         fp = fopen(filename, "rb");
201         if (!fp)
202                 Fatal("Unable to open file %s: %s\n", filename,
203                       strerror(errno));
204
205         buf = malloc(file_size);
206         if (1 != fread(buf, file_size, 1, fp))
207                 Fatal("Unable to read entirety of %s: %s\n", filename,
208                       error_fread(fp));
209
210         if (size_ptr)
211                 *size_ptr = file_size;
212
213         return buf;
214 }
215
216 /****************************************************************************/
217
218 static int do_vbutil_kernel(int argc, char *argv[])
219 {
220         char *filename = NULL;
221         char *oldfile = NULL;
222         char *keyblock_file = NULL;
223         char *signpubkey_file = NULL;
224         char *signprivkey_file = NULL;
225         char *version_str = NULL;
226         int version = -1;
227         char *vmlinuz_file = NULL;
228         char *bootloader_file = NULL;
229         char *config_file = NULL;
230         char *vmlinuz_out_file = NULL;
231         enum arch_t arch = ARCH_X86;
232         uint64_t kernel_body_load_address = CROS_32BIT_ENTRY_ADDR;
233         int mode = 0;
234         int parse_error = 0;
235         uint64_t min_version = 0;
236         char *e;
237         int i = 0;
238         int errcount = 0;
239         int rv;
240         struct vb2_keyblock *keyblock = NULL;
241         struct vb2_keyblock *t_keyblock = NULL;
242         VbPrivateKey *signpriv_key = NULL;
243         VbPublicKey *signpub_key = NULL;
244         uint8_t *kpart_data = NULL;
245         uint64_t kpart_size = 0;
246         uint8_t *vmlinuz_buf = NULL;
247         uint64_t vmlinuz_size = 0;
248         uint8_t *t_config_data;
249         uint64_t t_config_size;
250         uint8_t *t_bootloader_data;
251         uint64_t t_bootloader_size;
252         uint64_t vmlinuz_header_size = 0;
253         uint64_t vmlinuz_header_address = 0;
254         uint64_t vmlinuz_header_offset = 0;
255         VbKernelPreambleHeader *preamble = NULL;
256         uint8_t *kblob_data = NULL;
257         uint64_t kblob_size = 0;
258         uint8_t *vblock_data = NULL;
259         uint64_t vblock_size = 0;
260         uint32_t flags = 0;
261         FILE *f;
262
263         while (((i = getopt_long(argc, argv, ":", long_opts, NULL)) != -1) &&
264                !parse_error) {
265                 switch (i) {
266                 default:
267                 case '?':
268                         /* Unhandled option */
269                         parse_error = 1;
270                         break;
271
272                 case 0:
273                         /* silently handled option */
274                         break;
275                 case OPT_HELP:
276                         print_help(argc, argv);
277                         return !!parse_error;
278
279                 case OPT_MODE_PACK:
280                 case OPT_MODE_REPACK:
281                 case OPT_MODE_VERIFY:
282                 case OPT_MODE_GET_VMLINUZ:
283                         if (mode && (mode != i)) {
284                                 fprintf(stderr,
285                                         "Only one mode can be specified\n");
286                                 parse_error = 1;
287                                 break;
288                         }
289                         mode = i;
290                         filename = optarg;
291                         break;
292
293                 case OPT_ARCH:
294                         /* check the first 3 characters to also detect x86_64 */
295                         if ((!strncasecmp(optarg, "x86", 3)) ||
296                             (!strcasecmp(optarg, "amd64")))
297                                 arch = ARCH_X86;
298                         else if ((!strcasecmp(optarg, "arm")) ||
299                                  (!strcasecmp(optarg, "aarch64")))
300                                 arch = ARCH_ARM;
301                         else if (!strcasecmp(optarg, "mips"))
302                                 arch = ARCH_MIPS;
303                         else {
304                                 fprintf(stderr,
305                                         "Unknown architecture string: %s\n",
306                                         optarg);
307                                 parse_error = 1;
308                         }
309                         break;
310
311                 case OPT_OLDBLOB:
312                         oldfile = optarg;
313                         break;
314
315                 case OPT_KLOADADDR:
316                         kernel_body_load_address = strtoul(optarg, &e, 0);
317                         if (!*optarg || (e && *e)) {
318                                 fprintf(stderr, "Invalid --kloadaddr\n");
319                                 parse_error = 1;
320                         }
321                         break;
322
323                 case OPT_KEYBLOCK:
324                         keyblock_file = optarg;
325                         break;
326
327                 case OPT_SIGNPUBKEY:
328                         signpubkey_file = optarg;
329                         break;
330
331                 case OPT_SIGNPRIVATE:
332                         signprivkey_file = optarg;
333                         break;
334
335                 case OPT_VMLINUZ:
336                         vmlinuz_file = optarg;
337                         break;
338
339                 case OPT_FLAGS:
340                         flags = (uint32_t)strtoul(optarg, &e, 0);
341                         if (!*optarg || (e && *e)) {
342                                 fprintf(stderr, "Invalid --flags\n");
343                                 parse_error = 1;
344                         }
345                         break;
346
347                 case OPT_BOOTLOADER:
348                         bootloader_file = optarg;
349                         break;
350
351                 case OPT_CONFIG:
352                         config_file = optarg;
353                         break;
354
355                 case OPT_VBLOCKONLY:
356                         opt_vblockonly = 1;
357                         break;
358
359                 case OPT_VERSION:
360                         version_str = optarg;
361                         version = strtoul(optarg, &e, 0);
362                         if (!*optarg || (e && *e)) {
363                                 fprintf(stderr, "Invalid --version\n");
364                                 parse_error = 1;
365                         }
366                         break;
367
368                 case OPT_MINVERSION:
369                         min_version = strtoul(optarg, &e, 0);
370                         if (!*optarg || (e && *e)) {
371                                 fprintf(stderr, "Invalid --minversion\n");
372                                 parse_error = 1;
373                         }
374                         break;
375
376                 case OPT_PAD:
377                         opt_pad = strtoul(optarg, &e, 0);
378                         if (!*optarg || (e && *e)) {
379                                 fprintf(stderr, "Invalid --pad\n");
380                                 parse_error = 1;
381                         }
382                         break;
383                 case OPT_VMLINUZ_OUT:
384                         vmlinuz_out_file = optarg;
385                 }
386         }
387
388         if (parse_error) {
389                 print_help(argc, argv);
390                 return 1;
391         }
392
393         switch (mode) {
394         case OPT_MODE_PACK:
395
396                 if (!keyblock_file)
397                         Fatal("Missing required keyblock file.\n");
398
399                 t_keyblock = (struct vb2_keyblock *)ReadFile(keyblock_file, 0);
400                 if (!t_keyblock)
401                         Fatal("Error reading key block.\n");
402
403                 if (!signprivkey_file)
404                         Fatal("Missing required signprivate file.\n");
405
406                 signpriv_key = PrivateKeyRead(signprivkey_file);
407                 if (!signpriv_key)
408                         Fatal("Error reading signing key.\n");
409
410                 if (!config_file)
411                         Fatal("Missing required config file.\n");
412
413                 Debug("Reading %s\n", config_file);
414                 t_config_data =
415                         ReadConfigFile(config_file, &t_config_size);
416                 if (!t_config_data)
417                         Fatal("Error reading config file.\n");
418
419                 if (!bootloader_file)
420                         Fatal("Missing required bootloader file.\n");
421
422                 Debug("Reading %s\n", bootloader_file);
423                 t_bootloader_data = ReadFile(bootloader_file,
424                                              &t_bootloader_size);
425                 if (!t_bootloader_data)
426                         Fatal("Error reading bootloader file.\n");
427                 Debug(" bootloader file size=0x%" PRIx64 "\n",
428                       t_bootloader_size);
429
430                 if (!vmlinuz_file)
431                         Fatal("Missing required vmlinuz file.\n");
432                 Debug("Reading %s\n", vmlinuz_file);
433                 vmlinuz_buf = ReadFile(vmlinuz_file, &vmlinuz_size);
434                 if (!vmlinuz_buf)
435                         Fatal("Error reading vmlinuz file.\n");
436                 Debug(" vmlinuz file size=0x%" PRIx64 "\n",
437                       vmlinuz_size);
438                 if (!vmlinuz_size)
439                         Fatal("Empty vmlinuz file\n");
440
441                 kblob_data = CreateKernelBlob(
442                         vmlinuz_buf, vmlinuz_size,
443                         arch, kernel_body_load_address,
444                         t_config_data, t_config_size,
445                         t_bootloader_data, t_bootloader_size,
446                         &kblob_size);
447                 if (!kblob_data)
448                         Fatal("Unable to create kernel blob\n");
449
450                 Debug("kblob_size = 0x%" PRIx64 "\n", kblob_size);
451
452                 vblock_data = SignKernelBlob(kblob_data, kblob_size, opt_pad,
453                                              version, kernel_body_load_address,
454                                              t_keyblock, signpriv_key, flags,
455                                              &vblock_size);
456                 if (!vblock_data)
457                         Fatal("Unable to sign kernel blob\n");
458
459                 Debug("vblock_size = 0x%" PRIx64 "\n", vblock_size);
460
461                 if (opt_vblockonly)
462                         rv = WriteSomeParts(filename,
463                                             vblock_data, vblock_size,
464                                             NULL, 0);
465                 else
466                         rv = WriteSomeParts(filename,
467                                             vblock_data, vblock_size,
468                                             kblob_data, kblob_size);
469                 return rv;
470
471         case OPT_MODE_REPACK:
472
473                 /* Required */
474
475                 if (!signprivkey_file)
476                         Fatal("Missing required signprivate file.\n");
477
478                 signpriv_key = PrivateKeyRead(signprivkey_file);
479                 if (!signpriv_key)
480                         Fatal("Error reading signing key.\n");
481
482                 if (!oldfile)
483                         Fatal("Missing previously packed blob.\n");
484
485                 /* Load the kernel partition */
486                 kpart_data = ReadOldKPartFromFileOrDie(oldfile, &kpart_size);
487
488                 /* Make sure we have a kernel partition */
489                 if (FILE_TYPE_KERN_PREAMBLE !=
490                     futil_file_type_buf(kpart_data, kpart_size))
491                         Fatal("%s is not a kernel blob\n", oldfile);
492
493                 kblob_data = UnpackKPart(kpart_data, kpart_size, opt_pad,
494                                          &keyblock, &preamble, &kblob_size);
495
496                 if (!kblob_data)
497                         Fatal("Unable to unpack kernel partition\n");
498
499                 kernel_body_load_address = preamble->body_load_address;
500
501                 /* Update the config if asked */
502                 if (config_file) {
503                         Debug("Reading %s\n", config_file);
504                         t_config_data =
505                                 ReadConfigFile(config_file, &t_config_size);
506                         if (!t_config_data)
507                                 Fatal("Error reading config file.\n");
508                         if (0 != UpdateKernelBlobConfig(
509                                     kblob_data, kblob_size,
510                                     t_config_data, t_config_size))
511                                 Fatal("Unable to update config\n");
512                 }
513
514                 if (!version_str)
515                         version = preamble->kernel_version;
516
517                 if (VbKernelHasFlags(preamble) == VBOOT_SUCCESS)
518                         flags = preamble->flags;
519
520                 if (keyblock_file) {
521                         t_keyblock = (struct vb2_keyblock *)
522                                 ReadFile(keyblock_file, 0);
523                         if (!t_keyblock)
524                                 Fatal("Error reading key block.\n");
525                 }
526
527                 /* Reuse previous body size */
528                 vblock_data = SignKernelBlob(kblob_data, kblob_size, opt_pad,
529                                              version, kernel_body_load_address,
530                                              t_keyblock ? t_keyblock : keyblock,
531                                              signpriv_key, flags, &vblock_size);
532                 if (!vblock_data)
533                         Fatal("Unable to sign kernel blob\n");
534
535                 if (opt_vblockonly)
536                         rv = WriteSomeParts(filename,
537                                             vblock_data, vblock_size,
538                                             NULL, 0);
539                 else
540                         rv = WriteSomeParts(filename,
541                                             vblock_data, vblock_size,
542                                             kblob_data, kblob_size);
543                 return rv;
544
545         case OPT_MODE_VERIFY:
546
547                 /* Optional */
548
549                 if (signpubkey_file) {
550                         signpub_key = PublicKeyRead(signpubkey_file);
551                         if (!signpub_key)
552                                 Fatal("Error reading public key.\n");
553                 }
554
555                 /* Do it */
556
557                 /* Load the kernel partition */
558                 kpart_data = ReadOldKPartFromFileOrDie(filename, &kpart_size);
559
560                 kblob_data = UnpackKPart(kpart_data, kpart_size, opt_pad,
561                                          0, 0, &kblob_size);
562                 if (!kblob_data)
563                         Fatal("Unable to unpack kernel partition\n");
564
565                 rv = VerifyKernelBlob(kblob_data, kblob_size,
566                                       signpub_key, keyblock_file, min_version);
567
568                 return rv;
569
570         case OPT_MODE_GET_VMLINUZ:
571
572                 if (!vmlinuz_out_file) {
573                         fprintf(stderr,
574                                 "USE: vbutil_kernel --get-vmlinuz <file> "
575                                 "--vmlinuz-out <file>\n");
576                         print_help(argc, argv);
577                         return 1;
578                 }
579
580                 kpart_data = ReadOldKPartFromFileOrDie(filename, &kpart_size);
581
582                 kblob_data = UnpackKPart(kpart_data, kpart_size, opt_pad,
583                                          &keyblock, &preamble, &kblob_size);
584
585                 if (!kblob_data)
586                         Fatal("Unable to unpack kernel partition\n");
587
588                 f = fopen(vmlinuz_out_file, "wb");
589                 if (!f) {
590                         VbExError("Can't open output file %s\n",
591                                   vmlinuz_out_file);
592                         return 1;
593                 }
594
595                 /* Now stick 16-bit header followed by kernel block into
596                    output */
597                 if (VbGetKernelVmlinuzHeader(preamble,
598                                              &vmlinuz_header_address,
599                                              &vmlinuz_header_size)
600                     != VBOOT_SUCCESS) {
601                         Fatal("Unable to retrieve Vmlinuz Header!");
602                 }
603
604                 if (vmlinuz_header_size) {
605                         // verify that the 16-bit header is included in the
606                         // kblob (to make sure that it's included in the
607                         // signature)
608                         if (VerifyVmlinuzInsideKBlob(preamble->body_load_address,
609                                                      kblob_size,
610                                                      vmlinuz_header_address,
611                                                      vmlinuz_header_size)) {
612                                 VbExError("Vmlinuz header not signed!\n");
613                                 fclose(f);
614                                 unlink(vmlinuz_out_file);
615                                 return 1;
616                         }
617                         // calculate the vmlinuz_header offset from
618                         // the beginning of the kpart_data.  The kblob doesn't
619                         // include the body_load_offset, but does include
620                         // the keyblock and preamble sections.
621                         vmlinuz_header_offset = vmlinuz_header_address -
622                                 preamble->body_load_address +
623                                 keyblock->keyblock_size +
624                                 preamble->preamble_size;
625                         errcount |=
626                                 (1 != fwrite(kpart_data + vmlinuz_header_offset,
627                                              vmlinuz_header_size,
628                                              1,
629                                              f));
630                 }
631                 errcount |= (1 != fwrite(kblob_data,
632                                          kblob_size,
633                                          1,
634                                          f));
635                 if (errcount) {
636                         VbExError("Can't write output file %s\n",
637                                   vmlinuz_out_file);
638                         fclose(f);
639                         unlink(vmlinuz_out_file);
640                         return 1;
641                 }
642
643                 fclose(f);
644                 return 0;
645         }
646
647         fprintf(stderr,
648                 "You must specify a mode: "
649                 "--pack, --repack, --verify, or --get-vmlinuz\n");
650         print_help(argc, argv);
651         return 1;
652 }
653
654 DECLARE_FUTIL_COMMAND(vbutil_kernel, do_vbutil_kernel, VBOOT_VERSION_1_0,
655                       "Creates, signs, and verifies the kernel partition");