blob: a1ac5ab8d3cfaa609c537812582e11e2ad4ead66 [file] [log] [blame]
Bill Richardsonf318ee22014-09-23 14:30:30 -07001/*
2 * Copyright 2014 The Chromium OS Authors. All rights reserved.
Randall Spangler7d6898d2010-06-11 09:22:13 -07003 * 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
Bill Richardsona08b5c92010-06-30 21:59:43 -07009#include <errno.h>
Vincent Palatin56c85db2012-09-05 15:35:12 -070010#include <fcntl.h>
Randall Spangler7d6898d2010-06-11 09:22:13 -070011#include <getopt.h>
Bill Richardson31d95c22014-08-24 22:07:17 -070012#include <inttypes.h> /* For PRIu64 */
David Riley05987b12015-02-05 19:22:49 -080013#ifndef HAVE_MACOS
Bill Richardson31d95c22014-08-24 22:07:17 -070014#include <linux/fs.h> /* For BLKGETSIZE64 */
David Riley05987b12015-02-05 19:22:49 -080015#endif
Bill Richardson249677d2010-06-23 11:16:37 -070016#include <stdarg.h>
Randall Spangler7d6898d2010-06-11 09:22:13 -070017#include <stdio.h>
Bill Richardsona08b5c92010-06-30 21:59:43 -070018#include <string.h>
Bill Richardsonf318ee22014-09-23 14:30:30 -070019#include <sys/ioctl.h>
Bill Richardsona08b5c92010-06-30 21:59:43 -070020#include <sys/stat.h>
Randall Spangler7d6898d2010-06-11 09:22:13 -070021#include <unistd.h>
22
Bill Richardson25593382015-01-30 12:22:28 -080023#include "file_type.h"
Bill Richardson6f396152014-07-15 12:52:19 -070024#include "futility.h"
Randall Spangler7d6898d2010-06-11 09:22:13 -070025#include "host_common.h"
26#include "kernel_blob.h"
Bill Richardson9bfe2c92015-01-27 12:21:04 -080027#include "traversal.h"
Bill Richardsonf318ee22014-09-23 14:30:30 -070028#include "vb1_helper.h"
29
30static 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}
Randall Spangler7d6898d2010-06-11 09:22:13 -070039
Bill Richardson72e344d2012-03-19 12:47:18 -070040/* Global opts */
Bill Richardson779796f2014-09-23 11:47:40 -070041static int opt_verbose;
42static int opt_vblockonly;
Bill Richardson72e344d2012-03-19 12:47:18 -070043static uint64_t opt_pad = 65536;
Bill Richardson249677d2010-06-23 11:16:37 -070044
Randall Spangler7d6898d2010-06-11 09:22:13 -070045/* Command line options */
46enum {
Bill Richardson31d95c22014-08-24 22:07:17 -070047 OPT_MODE_PACK = 1000,
48 OPT_MODE_REPACK,
49 OPT_MODE_VERIFY,
Shelley Chenf1f53b32015-01-08 09:13:44 -080050 OPT_MODE_GET_VMLINUZ,
Bill Richardson31d95c22014-08-24 22:07:17 -070051 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,
Shelley Chenf1f53b32015-01-08 09:13:44 -080065 OPT_VMLINUZ_OUT,
Furquan Shaikh80e779d2015-02-03 15:34:29 -080066 OPT_FLAGS,
Randall Spangler7d6898d2010-06-11 09:22:13 -070067};
68
Mike Frysinger7351ed72014-08-18 10:47:42 -040069static const struct option long_opts[] = {
Bill Richardson31d95c22014-08-24 22:07:17 -070070 {"pack", 1, 0, OPT_MODE_PACK},
71 {"repack", 1, 0, OPT_MODE_REPACK},
72 {"verify", 1, 0, OPT_MODE_VERIFY},
Shelley Chenf1f53b32015-01-08 09:13:44 -080073 {"get-vmlinuz", 1, 0, OPT_MODE_GET_VMLINUZ},
Bill Richardson31d95c22014-08-24 22:07:17 -070074 {"arch", 1, 0, OPT_ARCH},
75 {"oldblob", 1, 0, OPT_OLDBLOB},
76 {"kloadaddr", 1, 0, OPT_KLOADADDR},
77 {"keyblock", 1, 0, OPT_KEYBLOCK},
78 {"signpubkey", 1, 0, OPT_SIGNPUBKEY},
79 {"signprivate", 1, 0, OPT_SIGNPRIVATE},
80 {"version", 1, 0, OPT_VERSION},
81 {"minversion", 1, 0, OPT_MINVERSION},
82 {"vmlinuz", 1, 0, OPT_VMLINUZ},
83 {"bootloader", 1, 0, OPT_BOOTLOADER},
84 {"config", 1, 0, OPT_CONFIG},
85 {"vblockonly", 0, 0, OPT_VBLOCKONLY},
86 {"pad", 1, 0, OPT_PAD},
87 {"verbose", 0, &opt_verbose, 1},
Bill Richardsone192e7f2014-09-23 12:49:26 -070088 {"debug", 0, &debugging_enabled, 1},
Shelley Chenf1f53b32015-01-08 09:13:44 -080089 {"vmlinuz-out", 1, 0, OPT_VMLINUZ_OUT},
Furquan Shaikh80e779d2015-02-03 15:34:29 -080090 {"flags", 1, 0, OPT_FLAGS},
Bill Richardson31d95c22014-08-24 22:07:17 -070091 {NULL, 0, 0, 0}
Randall Spangler7d6898d2010-06-11 09:22:13 -070092};
93
94
Bill Richardson31d95c22014-08-24 22:07:17 -070095
96static const char usage[] =
Bill Richardson31d95c22014-08-24 22:07:17 -070097 "\n"
Bill Richardson779796f2014-09-23 11:47:40 -070098 "Usage: " MYNAME " %s --pack <file> [PARAMETERS]\n"
Bill Richardson31d95c22014-08-24 22:07:17 -070099 "\n"
100 " Required parameters:\n"
101 " --keyblock <file> Key block in .keyblock format\n"
102 " --signprivate <file> Private key to sign kernel data,\n"
103 " in .vbprivk format\n"
104 " --version <number> Kernel version\n"
105 " --vmlinuz <file> Linux kernel bzImage file\n"
106 " --bootloader <file> Bootloader stub\n"
107 " --config <file> Command line file\n"
108 " --arch <arch> Cpu architecture (default x86)\n"
109 "\n"
110 " Optional:\n"
111 " --kloadaddr <address> Assign kernel body load address\n"
112 " --pad <number> Verification padding size in bytes\n"
113 " --vblockonly Emit just the verification blob\n"
Furquan Shaikh80e779d2015-02-03 15:34:29 -0800114 " --flags NUM Flags to be passed in the header\n"
Bill Richardson31d95c22014-08-24 22:07:17 -0700115 "\nOR\n\n"
Bill Richardson779796f2014-09-23 11:47:40 -0700116 "Usage: " MYNAME " %s --repack <file> [PARAMETERS]\n"
Bill Richardson31d95c22014-08-24 22:07:17 -0700117 "\n"
118 " Required parameters:\n"
119 " --signprivate <file> Private key to sign kernel data,\n"
120 " in .vbprivk format\n"
121 " --oldblob <file> Previously packed kernel blob\n"
122 " (including verfication blob)\n"
123 "\n"
124 " Optional:\n"
125 " --keyblock <file> Key block in .keyblock format\n"
126 " --config <file> New command line file\n"
127 " --version <number> Kernel version\n"
128 " --kloadaddr <address> Assign kernel body load address\n"
129 " --pad <number> Verification blob size in bytes\n"
130 " --vblockonly Emit just the verification blob\n"
131 "\nOR\n\n"
Bill Richardson779796f2014-09-23 11:47:40 -0700132 "Usage: " MYNAME " %s --verify <file> [PARAMETERS]\n"
Bill Richardson31d95c22014-08-24 22:07:17 -0700133 "\n"
134 " Optional:\n"
135 " --signpubkey <file>"
136 " Public key to verify kernel keyblock,\n"
137 " in .vbpubk format\n"
138 " --verbose Print a more detailed report\n"
139 " --keyblock <file> Outputs the verified key block,\n"
140 " in .keyblock format\n"
141 " --pad <number> Verification padding size in bytes\n"
142 " --minversion <number> Minimum combined kernel key version\n"
Shelley Chenf1f53b32015-01-08 09:13:44 -0800143 "\nOR\n\n"
144 "Usage: " MYNAME " %s --get-vmlinuz <file> [PARAMETERS]\n"
145 "\n"
146 " Required parameters:\n"
147 " --vmlinuz-out <file> vmlinuz image output file\n"
Bill Richardson31d95c22014-08-24 22:07:17 -0700148 "\n";
149
150
Randall Spangler7d6898d2010-06-11 09:22:13 -0700151/* Print help and return error */
Bill Richardson779796f2014-09-23 11:47:40 -0700152static void print_help(const char *progname)
Bill Richardson31d95c22014-08-24 22:07:17 -0700153{
Shelley Chenf1f53b32015-01-08 09:13:44 -0800154 printf(usage, progname, progname, progname, progname);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700155}
156
Bill Richardson72e344d2012-03-19 12:47:18 -0700157
Bill Richardson2f6a71f2010-10-14 09:25:39 -0700158/* Return an explanation when fread() fails. */
Bill Richardson779796f2014-09-23 11:47:40 -0700159static const char *error_fread(FILE *fp)
Bill Richardson31d95c22014-08-24 22:07:17 -0700160{
161 const char *retval = "beats me why";
162 if (feof(fp))
163 retval = "EOF";
164 else if (ferror(fp))
165 retval = strerror(errno);
166 clearerr(fp);
167 return retval;
Bill Richardson2f6a71f2010-10-14 09:25:39 -0700168}
Randall Spangler7d6898d2010-06-11 09:22:13 -0700169
Randall Spangler7d6898d2010-06-11 09:22:13 -0700170
Bill Richardsonf318ee22014-09-23 14:30:30 -0700171/* This reads a complete kernel partition into a buffer */
172static uint8_t *ReadOldKPartFromFileOrDie(const char *filename,
Bill Richardson779796f2014-09-23 11:47:40 -0700173 uint64_t *size_ptr)
Bill Richardson31d95c22014-08-24 22:07:17 -0700174{
175 FILE *fp = NULL;
176 struct stat statbuf;
Bill Richardson31d95c22014-08-24 22:07:17 -0700177 uint8_t *buf;
Bill Richardson31d95c22014-08-24 22:07:17 -0700178 uint64_t file_size = 0;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700179
Bill Richardson31d95c22014-08-24 22:07:17 -0700180 if (0 != stat(filename, &statbuf))
181 Fatal("Unable to stat %s: %s\n", filename, strerror(errno));
Bill Richardsona08b5c92010-06-30 21:59:43 -0700182
Bill Richardson31d95c22014-08-24 22:07:17 -0700183 if (S_ISBLK(statbuf.st_mode)) {
David Riley05987b12015-02-05 19:22:49 -0800184#ifndef HAVE_MACOS
Bill Richardson779796f2014-09-23 11:47:40 -0700185 int fd = open(filename, O_RDONLY);
186 if (fd >= 0) {
Bill Richardson31d95c22014-08-24 22:07:17 -0700187 ioctl(fd, BLKGETSIZE64, &file_size);
188 close(fd);
189 }
David Riley05987b12015-02-05 19:22:49 -0800190#endif
Bill Richardson31d95c22014-08-24 22:07:17 -0700191 } else {
192 file_size = statbuf.st_size;
193 }
194 Debug("%s size is 0x%" PRIx64 "\n", filename, file_size);
195 if (file_size < opt_pad)
Jinguang Dong3268d792017-04-10 16:02:29 +0800196 Fatal("%s is too small to be a valid kernel blob\n", filename);
Bill Richardsona08b5c92010-06-30 21:59:43 -0700197
Bill Richardson31d95c22014-08-24 22:07:17 -0700198 Debug("Reading %s\n", filename);
199 fp = fopen(filename, "rb");
200 if (!fp)
201 Fatal("Unable to open file %s: %s\n", filename,
202 strerror(errno));
Bill Richardsona08b5c92010-06-30 21:59:43 -0700203
Bill Richardsonf318ee22014-09-23 14:30:30 -0700204 buf = malloc(file_size);
205 if (1 != fread(buf, file_size, 1, fp))
206 Fatal("Unable to read entirety of %s: %s\n", filename,
Bill Richardson31d95c22014-08-24 22:07:17 -0700207 error_fread(fp));
vbendebb2b0fcc2010-07-15 15:09:47 -0700208
Bill Richardson31d95c22014-08-24 22:07:17 -0700209 if (size_ptr)
Bill Richardsonf318ee22014-09-23 14:30:30 -0700210 *size_ptr = file_size;
Bill Richardson72e344d2012-03-19 12:47:18 -0700211
Bill Richardsonf318ee22014-09-23 14:30:30 -0700212 return buf;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700213}
214
Bill Richardson72e344d2012-03-19 12:47:18 -0700215/****************************************************************************/
Randall Spangler7d6898d2010-06-11 09:22:13 -0700216
Bill Richardson4dad6902014-12-03 16:13:33 -0800217static int do_vbutil_kernel(int argc, char *argv[])
Bill Richardson31d95c22014-08-24 22:07:17 -0700218{
219 char *filename = NULL;
220 char *oldfile = NULL;
221 char *keyblock_file = NULL;
222 char *signpubkey_file = NULL;
223 char *signprivkey_file = NULL;
224 char *version_str = NULL;
225 int version = -1;
226 char *vmlinuz_file = NULL;
227 char *bootloader_file = NULL;
228 char *config_file = NULL;
Shelley Chenf1f53b32015-01-08 09:13:44 -0800229 char *vmlinuz_out_file = NULL;
Bill Richardsone192e7f2014-09-23 12:49:26 -0700230 enum arch_t arch = ARCH_X86;
Bill Richardson31d95c22014-08-24 22:07:17 -0700231 uint64_t kernel_body_load_address = CROS_32BIT_ENTRY_ADDR;
232 int mode = 0;
233 int parse_error = 0;
234 uint64_t min_version = 0;
235 char *e;
Shelley Chenf1f53b32015-01-08 09:13:44 -0800236 int i = 0;
Shelley Chen1bdc6122015-02-02 10:06:10 -0800237 int errcount = 0;
Bill Richardsonf318ee22014-09-23 14:30:30 -0700238 int rv;
239 VbKeyBlockHeader *keyblock = NULL;
240 VbKeyBlockHeader *t_keyblock = NULL;
Bill Richardson31d95c22014-08-24 22:07:17 -0700241 VbPrivateKey *signpriv_key = NULL;
242 VbPublicKey *signpub_key = NULL;
Bill Richardsonf318ee22014-09-23 14:30:30 -0700243 uint8_t *kpart_data = NULL;
244 uint64_t kpart_size = 0;
245 uint8_t *vmlinuz_buf = NULL;
246 uint64_t vmlinuz_size = 0;
247 uint8_t *t_config_data;
248 uint64_t t_config_size;
249 uint8_t *t_bootloader_data;
250 uint64_t t_bootloader_size;
Shelley Chenf1f53b32015-01-08 09:13:44 -0800251 uint64_t vmlinuz_header_size = 0;
252 uint64_t vmlinuz_header_address = 0;
Shelley Chen1bdc6122015-02-02 10:06:10 -0800253 uint64_t vmlinuz_header_offset = 0;
Bill Richardsonf318ee22014-09-23 14:30:30 -0700254 VbKernelPreambleHeader *preamble = NULL;
255 uint8_t *kblob_data = NULL;
256 uint64_t kblob_size = 0;
257 uint8_t *vblock_data = NULL;
258 uint64_t vblock_size = 0;
Furquan Shaikh80e779d2015-02-03 15:34:29 -0800259 uint32_t flags = 0;
Shelley Chenf1f53b32015-01-08 09:13:44 -0800260 FILE *f;
Bill Richardson72e344d2012-03-19 12:47:18 -0700261
Bill Richardson31d95c22014-08-24 22:07:17 -0700262 while (((i = getopt_long(argc, argv, ":", long_opts, NULL)) != -1) &&
263 !parse_error) {
264 switch (i) {
265 default:
266 case '?':
267 /* Unhandled option */
268 parse_error = 1;
269 break;
Bill Richardson72e344d2012-03-19 12:47:18 -0700270
Bill Richardson31d95c22014-08-24 22:07:17 -0700271 case 0:
272 /* silently handled option */
273 break;
Bill Richardson72e344d2012-03-19 12:47:18 -0700274
Bill Richardson31d95c22014-08-24 22:07:17 -0700275 case OPT_MODE_PACK:
276 case OPT_MODE_REPACK:
277 case OPT_MODE_VERIFY:
Shelley Chenf1f53b32015-01-08 09:13:44 -0800278 case OPT_MODE_GET_VMLINUZ:
Bill Richardson31d95c22014-08-24 22:07:17 -0700279 if (mode && (mode != i)) {
280 fprintf(stderr,
281 "Only one mode can be specified\n");
282 parse_error = 1;
283 break;
284 }
285 mode = i;
286 filename = optarg;
287 break;
Bill Richardson72e344d2012-03-19 12:47:18 -0700288
Bill Richardson31d95c22014-08-24 22:07:17 -0700289 case OPT_ARCH:
290 /* check the first 3 characters to also detect x86_64 */
291 if ((!strncasecmp(optarg, "x86", 3)) ||
292 (!strcasecmp(optarg, "amd64")))
293 arch = ARCH_X86;
294 else if ((!strcasecmp(optarg, "arm")) ||
295 (!strcasecmp(optarg, "aarch64")))
296 arch = ARCH_ARM;
297 else if (!strcasecmp(optarg, "mips"))
298 arch = ARCH_MIPS;
299 else {
300 fprintf(stderr,
301 "Unknown architecture string: %s\n",
302 optarg);
303 parse_error = 1;
304 }
305 break;
Bill Richardson72e344d2012-03-19 12:47:18 -0700306
Bill Richardson31d95c22014-08-24 22:07:17 -0700307 case OPT_OLDBLOB:
308 oldfile = optarg;
309 break;
Bill Richardson72e344d2012-03-19 12:47:18 -0700310
Bill Richardson31d95c22014-08-24 22:07:17 -0700311 case OPT_KLOADADDR:
Bill Richardson31d95c22014-08-24 22:07:17 -0700312 kernel_body_load_address = strtoul(optarg, &e, 0);
313 if (!*optarg || (e && *e)) {
314 fprintf(stderr, "Invalid --kloadaddr\n");
315 parse_error = 1;
316 }
317 break;
Bill Richardson72e344d2012-03-19 12:47:18 -0700318
Bill Richardson31d95c22014-08-24 22:07:17 -0700319 case OPT_KEYBLOCK:
320 keyblock_file = optarg;
321 break;
Bill Richardson72e344d2012-03-19 12:47:18 -0700322
Bill Richardson31d95c22014-08-24 22:07:17 -0700323 case OPT_SIGNPUBKEY:
324 signpubkey_file = optarg;
325 break;
Bill Richardson72e344d2012-03-19 12:47:18 -0700326
Bill Richardson31d95c22014-08-24 22:07:17 -0700327 case OPT_SIGNPRIVATE:
328 signprivkey_file = optarg;
329 break;
Bill Richardson72e344d2012-03-19 12:47:18 -0700330
Bill Richardson31d95c22014-08-24 22:07:17 -0700331 case OPT_VMLINUZ:
332 vmlinuz_file = optarg;
333 break;
Bill Richardson72e344d2012-03-19 12:47:18 -0700334
Furquan Shaikh80e779d2015-02-03 15:34:29 -0800335 case OPT_FLAGS:
336 flags = (uint32_t)strtoul(optarg, &e, 0);
337 if (!*optarg || (e && *e)) {
338 fprintf(stderr, "Invalid --flags\n");
339 parse_error = 1;
340 }
341 break;
342
Bill Richardson31d95c22014-08-24 22:07:17 -0700343 case OPT_BOOTLOADER:
344 bootloader_file = optarg;
345 break;
Bill Richardson72e344d2012-03-19 12:47:18 -0700346
Bill Richardson31d95c22014-08-24 22:07:17 -0700347 case OPT_CONFIG:
348 config_file = optarg;
349 break;
Bill Richardson72e344d2012-03-19 12:47:18 -0700350
Bill Richardson31d95c22014-08-24 22:07:17 -0700351 case OPT_VBLOCKONLY:
352 opt_vblockonly = 1;
353 break;
Bill Richardson72e344d2012-03-19 12:47:18 -0700354
Bill Richardson31d95c22014-08-24 22:07:17 -0700355 case OPT_VERSION:
356 version_str = optarg;
357 version = strtoul(optarg, &e, 0);
358 if (!*optarg || (e && *e)) {
359 fprintf(stderr, "Invalid --version\n");
360 parse_error = 1;
361 }
362 break;
Bill Richardson72e344d2012-03-19 12:47:18 -0700363
Bill Richardson31d95c22014-08-24 22:07:17 -0700364 case OPT_MINVERSION:
365 min_version = strtoul(optarg, &e, 0);
366 if (!*optarg || (e && *e)) {
367 fprintf(stderr, "Invalid --minversion\n");
368 parse_error = 1;
369 }
370 break;
Bill Richardson72e344d2012-03-19 12:47:18 -0700371
Bill Richardson31d95c22014-08-24 22:07:17 -0700372 case OPT_PAD:
373 opt_pad = strtoul(optarg, &e, 0);
374 if (!*optarg || (e && *e)) {
375 fprintf(stderr, "Invalid --pad\n");
376 parse_error = 1;
377 }
378 break;
Shelley Chenf1f53b32015-01-08 09:13:44 -0800379 case OPT_VMLINUZ_OUT:
380 vmlinuz_out_file = optarg;
Bill Richardson31d95c22014-08-24 22:07:17 -0700381 }
382 }
Bill Richardson72e344d2012-03-19 12:47:18 -0700383
Bill Richardson779796f2014-09-23 11:47:40 -0700384 if (parse_error) {
385 print_help(argv[0]);
386 return 1;
387 }
Bill Richardson72e344d2012-03-19 12:47:18 -0700388
Bill Richardson31d95c22014-08-24 22:07:17 -0700389 switch (mode) {
390 case OPT_MODE_PACK:
Bill Richardson72e344d2012-03-19 12:47:18 -0700391
Bill Richardson31d95c22014-08-24 22:07:17 -0700392 if (!keyblock_file)
393 Fatal("Missing required keyblock file.\n");
Bill Richardson72e344d2012-03-19 12:47:18 -0700394
Bill Richardsonf318ee22014-09-23 14:30:30 -0700395 t_keyblock = (VbKeyBlockHeader *)ReadFile(keyblock_file, 0);
396 if (!t_keyblock)
Bill Richardson31d95c22014-08-24 22:07:17 -0700397 Fatal("Error reading key block.\n");
Bill Richardson72e344d2012-03-19 12:47:18 -0700398
Bill Richardson31d95c22014-08-24 22:07:17 -0700399 if (!signprivkey_file)
400 Fatal("Missing required signprivate file.\n");
Bill Richardson72e344d2012-03-19 12:47:18 -0700401
Bill Richardson31d95c22014-08-24 22:07:17 -0700402 signpriv_key = PrivateKeyRead(signprivkey_file);
403 if (!signpriv_key)
404 Fatal("Error reading signing key.\n");
Bill Richardson72e344d2012-03-19 12:47:18 -0700405
Bill Richardsonf318ee22014-09-23 14:30:30 -0700406 if (!config_file)
407 Fatal("Missing required config file.\n");
Bill Richardson72e344d2012-03-19 12:47:18 -0700408
Bill Richardsonf318ee22014-09-23 14:30:30 -0700409 Debug("Reading %s\n", config_file);
410 t_config_data =
411 ReadConfigFile(config_file, &t_config_size);
412 if (!t_config_data)
413 Fatal("Error reading config file.\n");
Bill Richardson72e344d2012-03-19 12:47:18 -0700414
Bill Richardsonf318ee22014-09-23 14:30:30 -0700415 if (!bootloader_file)
416 Fatal("Missing required bootloader file.\n");
Bill Richardson72e344d2012-03-19 12:47:18 -0700417
Bill Richardsonf318ee22014-09-23 14:30:30 -0700418 Debug("Reading %s\n", bootloader_file);
419 t_bootloader_data = ReadFile(bootloader_file,
420 &t_bootloader_size);
421 if (!t_bootloader_data)
422 Fatal("Error reading bootloader file.\n");
423 Debug(" bootloader file size=0x%" PRIx64 "\n",
424 t_bootloader_size);
Bill Richardson72e344d2012-03-19 12:47:18 -0700425
Bill Richardsonf318ee22014-09-23 14:30:30 -0700426 if (!vmlinuz_file)
427 Fatal("Missing required vmlinuz file.\n");
428 Debug("Reading %s\n", vmlinuz_file);
429 vmlinuz_buf = ReadFile(vmlinuz_file, &vmlinuz_size);
430 if (!vmlinuz_buf)
431 Fatal("Error reading vmlinuz file.\n");
432 Debug(" vmlinuz file size=0x%" PRIx64 "\n",
433 vmlinuz_size);
434 if (!vmlinuz_size)
435 Fatal("Empty vmlinuz file\n");
Bill Richardson31d95c22014-08-24 22:07:17 -0700436
Bill Richardsonf318ee22014-09-23 14:30:30 -0700437 kblob_data = CreateKernelBlob(
438 vmlinuz_buf, vmlinuz_size,
439 arch, kernel_body_load_address,
440 t_config_data, t_config_size,
441 t_bootloader_data, t_bootloader_size,
442 &kblob_size);
443 if (!kblob_data)
444 Fatal("Unable to create kernel blob\n");
Bill Richardson31d95c22014-08-24 22:07:17 -0700445
Bill Richardsonf318ee22014-09-23 14:30:30 -0700446 Debug("kblob_size = 0x%" PRIx64 "\n", kblob_size);
447
448 vblock_data = SignKernelBlob(kblob_data, kblob_size, opt_pad,
449 version, kernel_body_load_address,
Furquan Shaikh80e779d2015-02-03 15:34:29 -0800450 t_keyblock, signpriv_key, flags,
Bill Richardsonf318ee22014-09-23 14:30:30 -0700451 &vblock_size);
452 if (!vblock_data)
453 Fatal("Unable to sign kernel blob\n");
454
455 Debug("vblock_size = 0x%" PRIx64 "\n", vblock_size);
456
457 if (opt_vblockonly)
458 rv = WriteSomeParts(filename,
459 vblock_data, vblock_size,
460 NULL, 0);
461 else
462 rv = WriteSomeParts(filename,
463 vblock_data, vblock_size,
464 kblob_data, kblob_size);
465 return rv;
Bill Richardson31d95c22014-08-24 22:07:17 -0700466
467 case OPT_MODE_REPACK:
468
469 /* Required */
470
471 if (!signprivkey_file)
472 Fatal("Missing required signprivate file.\n");
473
474 signpriv_key = PrivateKeyRead(signprivkey_file);
475 if (!signpriv_key)
476 Fatal("Error reading signing key.\n");
477
478 if (!oldfile)
479 Fatal("Missing previously packed blob.\n");
480
Bill Richardsonf318ee22014-09-23 14:30:30 -0700481 /* Load the kernel partition */
482 kpart_data = ReadOldKPartFromFileOrDie(oldfile, &kpart_size);
Bill Richardson31d95c22014-08-24 22:07:17 -0700483
Bill Richardson9bfe2c92015-01-27 12:21:04 -0800484 /* Make sure we have a kernel partition */
485 if (FILE_TYPE_KERN_PREAMBLE !=
Bill Richardson25593382015-01-30 12:22:28 -0800486 futil_file_type_buf(kpart_data, kpart_size))
Bill Richardson9bfe2c92015-01-27 12:21:04 -0800487 Fatal("%s is not a kernel blob\n", oldfile);
488
Bill Richardsonf318ee22014-09-23 14:30:30 -0700489 kblob_data = UnpackKPart(kpart_data, kpart_size, opt_pad,
490 &keyblock, &preamble, &kblob_size);
Bill Richardson31d95c22014-08-24 22:07:17 -0700491
Bill Richardsonf318ee22014-09-23 14:30:30 -0700492 if (!kblob_data)
493 Fatal("Unable to unpack kernel partition\n");
Bill Richardson31d95c22014-08-24 22:07:17 -0700494
Bill Richardsonf318ee22014-09-23 14:30:30 -0700495 kernel_body_load_address = preamble->body_load_address;
Bill Richardson31d95c22014-08-24 22:07:17 -0700496
Bill Richardsonf318ee22014-09-23 14:30:30 -0700497 /* Update the config if asked */
Bill Richardson31d95c22014-08-24 22:07:17 -0700498 if (config_file) {
Bill Richardson31d95c22014-08-24 22:07:17 -0700499 Debug("Reading %s\n", config_file);
Bill Richardsonf318ee22014-09-23 14:30:30 -0700500 t_config_data =
501 ReadConfigFile(config_file, &t_config_size);
502 if (!t_config_data)
Bill Richardson31d95c22014-08-24 22:07:17 -0700503 Fatal("Error reading config file.\n");
Bill Richardsonf318ee22014-09-23 14:30:30 -0700504 if (0 != UpdateKernelBlobConfig(
505 kblob_data, kblob_size,
506 t_config_data, t_config_size))
507 Fatal("Unable to update config\n");
Bill Richardson31d95c22014-08-24 22:07:17 -0700508 }
509
Bill Richardsonf318ee22014-09-23 14:30:30 -0700510 if (!version_str)
511 version = preamble->kernel_version;
512
Furquan Shaikh80e779d2015-02-03 15:34:29 -0800513 if (VbKernelHasFlags(preamble) == VBOOT_SUCCESS)
514 flags = preamble->flags;
515
Bill Richardson31d95c22014-08-24 22:07:17 -0700516 if (keyblock_file) {
Bill Richardsonf318ee22014-09-23 14:30:30 -0700517 t_keyblock =
518 (VbKeyBlockHeader *)ReadFile(keyblock_file, 0);
519 if (!t_keyblock)
Bill Richardson31d95c22014-08-24 22:07:17 -0700520 Fatal("Error reading key block.\n");
521 }
522
Bill Richardsonf1dba022014-10-01 14:10:45 -0700523 /* Reuse previous body size */
Bill Richardsonf318ee22014-09-23 14:30:30 -0700524 vblock_data = SignKernelBlob(kblob_data, kblob_size, opt_pad,
525 version, kernel_body_load_address,
526 t_keyblock ? t_keyblock : keyblock,
Furquan Shaikh80e779d2015-02-03 15:34:29 -0800527 signpriv_key, flags, &vblock_size);
Bill Richardsonf318ee22014-09-23 14:30:30 -0700528 if (!vblock_data)
529 Fatal("Unable to sign kernel blob\n");
Bill Richardson31d95c22014-08-24 22:07:17 -0700530
Bill Richardsonf318ee22014-09-23 14:30:30 -0700531 if (opt_vblockonly)
532 rv = WriteSomeParts(filename,
533 vblock_data, vblock_size,
534 NULL, 0);
535 else
536 rv = WriteSomeParts(filename,
537 vblock_data, vblock_size,
538 kblob_data, kblob_size);
539 return rv;
Bill Richardson31d95c22014-08-24 22:07:17 -0700540
541 case OPT_MODE_VERIFY:
542
543 /* Optional */
544
545 if (signpubkey_file) {
546 signpub_key = PublicKeyRead(signpubkey_file);
547 if (!signpub_key)
548 Fatal("Error reading public key.\n");
549 }
550
551 /* Do it */
552
Bill Richardsonf318ee22014-09-23 14:30:30 -0700553 /* Load the kernel partition */
554 kpart_data = ReadOldKPartFromFileOrDie(filename, &kpart_size);
Bill Richardson31d95c22014-08-24 22:07:17 -0700555
Bill Richardsonf318ee22014-09-23 14:30:30 -0700556 kblob_data = UnpackKPart(kpart_data, kpart_size, opt_pad,
557 0, 0, &kblob_size);
558 if (!kblob_data)
559 Fatal("Unable to unpack kernel partition\n");
560
561 rv = VerifyKernelBlob(kblob_data, kblob_size,
562 signpub_key, keyblock_file, min_version);
563
564 return rv;
Shelley Chenf1f53b32015-01-08 09:13:44 -0800565
566 case OPT_MODE_GET_VMLINUZ:
567
568 if (!vmlinuz_out_file) {
569 fprintf(stderr,
570 "USE: vbutil_kernel --get-vmlinuz <file> "
571 "--vmlinuz-out <file>\n");
572 print_help(argv[0]);
573 return 1;
574 }
575
576 kpart_data = ReadOldKPartFromFileOrDie(filename, &kpart_size);
577
578 kblob_data = UnpackKPart(kpart_data, kpart_size, opt_pad,
579 &keyblock, &preamble, &kblob_size);
580
581 if (!kblob_data)
582 Fatal("Unable to unpack kernel partition\n");
583
584 f = fopen(vmlinuz_out_file, "wb");
585 if (!f) {
586 VbExError("Can't open output file %s\n",
587 vmlinuz_out_file);
588 return 1;
589 }
590
591 /* Now stick 16-bit header followed by kernel block into
592 output */
593 if (VbGetKernelVmlinuzHeader(preamble,
594 &vmlinuz_header_address,
595 &vmlinuz_header_size)
596 != VBOOT_SUCCESS) {
597 Fatal("Unable to retrieve Vmlinuz Header!");
598 }
Shelley Chen1bdc6122015-02-02 10:06:10 -0800599
Shelley Chenf1f53b32015-01-08 09:13:44 -0800600 if (vmlinuz_header_size) {
601 // verify that the 16-bit header is included in the
602 // kblob (to make sure that it's included in the
603 // signature)
604 if (VerifyVmlinuzInsideKBlob(preamble->body_load_address,
605 kblob_size,
606 vmlinuz_header_address,
607 vmlinuz_header_size)) {
608 VbExError("Vmlinuz header not signed!\n");
609 fclose(f);
610 unlink(vmlinuz_out_file);
611 return 1;
612 }
Shelley Chen1bdc6122015-02-02 10:06:10 -0800613 // calculate the vmlinuz_header offset from
614 // the beginning of the kpart_data. The kblob doesn't
615 // include the body_load_offset, but does include
616 // the keyblock and preamble sections.
617 vmlinuz_header_offset = vmlinuz_header_address -
618 preamble->body_load_address +
619 keyblock->key_block_size +
620 preamble->preamble_size;
621 errcount |=
622 (1 != fwrite(kpart_data + vmlinuz_header_offset,
623 vmlinuz_header_size,
624 1,
625 f));
626 }
627 errcount |= (1 != fwrite(kblob_data,
628 kblob_size,
Shelley Chenf1f53b32015-01-08 09:13:44 -0800629 1,
630 f));
Shelley Chen1bdc6122015-02-02 10:06:10 -0800631 if (errcount) {
Shelley Chenf1f53b32015-01-08 09:13:44 -0800632 VbExError("Can't write output file %s\n",
633 vmlinuz_out_file);
634 fclose(f);
635 unlink(vmlinuz_out_file);
636 return 1;
637 }
638
639 fclose(f);
Shelley Chen1bdc6122015-02-02 10:06:10 -0800640 return 0;
Bill Richardson31d95c22014-08-24 22:07:17 -0700641 }
642
643 fprintf(stderr,
Shelley Chenf1f53b32015-01-08 09:13:44 -0800644 "You must specify a mode: "
645 "--pack, --repack, --verify, or --get-vmlinuz\n");
Bill Richardson779796f2014-09-23 11:47:40 -0700646 print_help(argv[0]);
647 return 1;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700648}
Bill Richardson6f396152014-07-15 12:52:19 -0700649
Bill Richardson4dad6902014-12-03 16:13:33 -0800650DECLARE_FUTIL_COMMAND(vbutil_kernel, do_vbutil_kernel,
Bill Richardson1eae8732015-02-05 12:36:15 -0800651 VBOOT_VERSION_1_0,
Bill Richardsonf318ee22014-09-23 14:30:30 -0700652 "Creates, signs, and verifies the kernel partition",
Bill Richardson779796f2014-09-23 11:47:40 -0700653 print_help);