blob: 3b2643e415ddf044c35257099c28a7bd1f8c2270 [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 */
Bill Richardson31d95c22014-08-24 22:07:17 -070013#include <linux/fs.h> /* For BLKGETSIZE64 */
Bill Richardson249677d2010-06-23 11:16:37 -070014#include <stdarg.h>
Randall Spangler7d6898d2010-06-11 09:22:13 -070015#include <stdio.h>
Bill Richardsona08b5c92010-06-30 21:59:43 -070016#include <string.h>
Bill Richardsonf318ee22014-09-23 14:30:30 -070017#include <sys/ioctl.h>
Bill Richardsona08b5c92010-06-30 21:59:43 -070018#include <sys/stat.h>
Randall Spangler7d6898d2010-06-11 09:22:13 -070019#include <unistd.h>
20
Bill Richardson6f396152014-07-15 12:52:19 -070021#include "futility.h"
Randall Spangler7d6898d2010-06-11 09:22:13 -070022#include "host_common.h"
23#include "kernel_blob.h"
Bill Richardsonf318ee22014-09-23 14:30:30 -070024#include "vb1_helper.h"
25
26static void Fatal(const char *format, ...)
27{
28 va_list ap;
29 va_start(ap, format);
30 fprintf(stderr, "ERROR: ");
31 vfprintf(stderr, format, ap);
32 va_end(ap);
33 exit(1);
34}
Randall Spangler7d6898d2010-06-11 09:22:13 -070035
Bill Richardson72e344d2012-03-19 12:47:18 -070036/* Global opts */
Bill Richardson779796f2014-09-23 11:47:40 -070037static int opt_verbose;
38static int opt_vblockonly;
Bill Richardson72e344d2012-03-19 12:47:18 -070039static uint64_t opt_pad = 65536;
Bill Richardson249677d2010-06-23 11:16:37 -070040
Randall Spangler7d6898d2010-06-11 09:22:13 -070041/* Command line options */
42enum {
Bill Richardson31d95c22014-08-24 22:07:17 -070043 OPT_MODE_PACK = 1000,
44 OPT_MODE_REPACK,
45 OPT_MODE_VERIFY,
Shelley Chenf1f53b32015-01-08 09:13:44 -080046 OPT_MODE_GET_VMLINUZ,
Bill Richardson31d95c22014-08-24 22:07:17 -070047 OPT_ARCH,
48 OPT_OLDBLOB,
49 OPT_KLOADADDR,
50 OPT_KEYBLOCK,
51 OPT_SIGNPUBKEY,
52 OPT_SIGNPRIVATE,
53 OPT_VERSION,
54 OPT_VMLINUZ,
55 OPT_BOOTLOADER,
56 OPT_CONFIG,
57 OPT_VBLOCKONLY,
58 OPT_PAD,
59 OPT_VERBOSE,
60 OPT_MINVERSION,
Shelley Chenf1f53b32015-01-08 09:13:44 -080061 OPT_VMLINUZ_OUT,
Randall Spangler7d6898d2010-06-11 09:22:13 -070062};
63
Mike Frysinger7351ed72014-08-18 10:47:42 -040064static const struct option long_opts[] = {
Bill Richardson31d95c22014-08-24 22:07:17 -070065 {"pack", 1, 0, OPT_MODE_PACK},
66 {"repack", 1, 0, OPT_MODE_REPACK},
67 {"verify", 1, 0, OPT_MODE_VERIFY},
Shelley Chenf1f53b32015-01-08 09:13:44 -080068 {"get-vmlinuz", 1, 0, OPT_MODE_GET_VMLINUZ},
Bill Richardson31d95c22014-08-24 22:07:17 -070069 {"arch", 1, 0, OPT_ARCH},
70 {"oldblob", 1, 0, OPT_OLDBLOB},
71 {"kloadaddr", 1, 0, OPT_KLOADADDR},
72 {"keyblock", 1, 0, OPT_KEYBLOCK},
73 {"signpubkey", 1, 0, OPT_SIGNPUBKEY},
74 {"signprivate", 1, 0, OPT_SIGNPRIVATE},
75 {"version", 1, 0, OPT_VERSION},
76 {"minversion", 1, 0, OPT_MINVERSION},
77 {"vmlinuz", 1, 0, OPT_VMLINUZ},
78 {"bootloader", 1, 0, OPT_BOOTLOADER},
79 {"config", 1, 0, OPT_CONFIG},
80 {"vblockonly", 0, 0, OPT_VBLOCKONLY},
81 {"pad", 1, 0, OPT_PAD},
82 {"verbose", 0, &opt_verbose, 1},
Bill Richardsone192e7f2014-09-23 12:49:26 -070083 {"debug", 0, &debugging_enabled, 1},
Shelley Chenf1f53b32015-01-08 09:13:44 -080084 {"vmlinuz-out", 1, 0, OPT_VMLINUZ_OUT},
Bill Richardson31d95c22014-08-24 22:07:17 -070085 {NULL, 0, 0, 0}
Randall Spangler7d6898d2010-06-11 09:22:13 -070086};
87
88
Bill Richardson31d95c22014-08-24 22:07:17 -070089
90static const char usage[] =
Bill Richardson31d95c22014-08-24 22:07:17 -070091 "\n"
Bill Richardson779796f2014-09-23 11:47:40 -070092 "Usage: " MYNAME " %s --pack <file> [PARAMETERS]\n"
Bill Richardson31d95c22014-08-24 22:07:17 -070093 "\n"
94 " Required parameters:\n"
95 " --keyblock <file> Key block in .keyblock format\n"
96 " --signprivate <file> Private key to sign kernel data,\n"
97 " in .vbprivk format\n"
98 " --version <number> Kernel version\n"
99 " --vmlinuz <file> Linux kernel bzImage file\n"
100 " --bootloader <file> Bootloader stub\n"
101 " --config <file> Command line file\n"
102 " --arch <arch> Cpu architecture (default x86)\n"
103 "\n"
104 " Optional:\n"
105 " --kloadaddr <address> Assign kernel body load address\n"
106 " --pad <number> Verification padding size in bytes\n"
107 " --vblockonly Emit just the verification blob\n"
108 "\nOR\n\n"
Bill Richardson779796f2014-09-23 11:47:40 -0700109 "Usage: " MYNAME " %s --repack <file> [PARAMETERS]\n"
Bill Richardson31d95c22014-08-24 22:07:17 -0700110 "\n"
111 " Required parameters:\n"
112 " --signprivate <file> Private key to sign kernel data,\n"
113 " in .vbprivk format\n"
114 " --oldblob <file> Previously packed kernel blob\n"
115 " (including verfication blob)\n"
116 "\n"
117 " Optional:\n"
118 " --keyblock <file> Key block in .keyblock format\n"
119 " --config <file> New command line file\n"
120 " --version <number> Kernel version\n"
121 " --kloadaddr <address> Assign kernel body load address\n"
122 " --pad <number> Verification blob size in bytes\n"
123 " --vblockonly Emit just the verification blob\n"
124 "\nOR\n\n"
Bill Richardson779796f2014-09-23 11:47:40 -0700125 "Usage: " MYNAME " %s --verify <file> [PARAMETERS]\n"
Bill Richardson31d95c22014-08-24 22:07:17 -0700126 "\n"
127 " Optional:\n"
128 " --signpubkey <file>"
129 " Public key to verify kernel keyblock,\n"
130 " in .vbpubk format\n"
131 " --verbose Print a more detailed report\n"
132 " --keyblock <file> Outputs the verified key block,\n"
133 " in .keyblock format\n"
134 " --pad <number> Verification padding size in bytes\n"
135 " --minversion <number> Minimum combined kernel key version\n"
Shelley Chenf1f53b32015-01-08 09:13:44 -0800136 "\nOR\n\n"
137 "Usage: " MYNAME " %s --get-vmlinuz <file> [PARAMETERS]\n"
138 "\n"
139 " Required parameters:\n"
140 " --vmlinuz-out <file> vmlinuz image output file\n"
Bill Richardson31d95c22014-08-24 22:07:17 -0700141 "\n";
142
143
Randall Spangler7d6898d2010-06-11 09:22:13 -0700144/* Print help and return error */
Bill Richardson779796f2014-09-23 11:47:40 -0700145static void print_help(const char *progname)
Bill Richardson31d95c22014-08-24 22:07:17 -0700146{
Shelley Chenf1f53b32015-01-08 09:13:44 -0800147 printf(usage, progname, progname, progname, progname);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700148}
149
Bill Richardson72e344d2012-03-19 12:47:18 -0700150
Bill Richardson2f6a71f2010-10-14 09:25:39 -0700151/* Return an explanation when fread() fails. */
Bill Richardson779796f2014-09-23 11:47:40 -0700152static const char *error_fread(FILE *fp)
Bill Richardson31d95c22014-08-24 22:07:17 -0700153{
154 const char *retval = "beats me why";
155 if (feof(fp))
156 retval = "EOF";
157 else if (ferror(fp))
158 retval = strerror(errno);
159 clearerr(fp);
160 return retval;
Bill Richardson2f6a71f2010-10-14 09:25:39 -0700161}
Randall Spangler7d6898d2010-06-11 09:22:13 -0700162
Randall Spangler7d6898d2010-06-11 09:22:13 -0700163
Bill Richardsonf318ee22014-09-23 14:30:30 -0700164/* This reads a complete kernel partition into a buffer */
165static uint8_t *ReadOldKPartFromFileOrDie(const char *filename,
Bill Richardson779796f2014-09-23 11:47:40 -0700166 uint64_t *size_ptr)
Bill Richardson31d95c22014-08-24 22:07:17 -0700167{
168 FILE *fp = NULL;
169 struct stat statbuf;
Bill Richardson31d95c22014-08-24 22:07:17 -0700170 uint8_t *buf;
Bill Richardson31d95c22014-08-24 22:07:17 -0700171 uint64_t file_size = 0;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700172
Bill Richardson31d95c22014-08-24 22:07:17 -0700173 if (0 != stat(filename, &statbuf))
174 Fatal("Unable to stat %s: %s\n", filename, strerror(errno));
Bill Richardsona08b5c92010-06-30 21:59:43 -0700175
Bill Richardson31d95c22014-08-24 22:07:17 -0700176 if (S_ISBLK(statbuf.st_mode)) {
Bill Richardson779796f2014-09-23 11:47:40 -0700177 int fd = open(filename, O_RDONLY);
178 if (fd >= 0) {
Bill Richardson31d95c22014-08-24 22:07:17 -0700179 ioctl(fd, BLKGETSIZE64, &file_size);
180 close(fd);
181 }
182 } else {
183 file_size = statbuf.st_size;
184 }
185 Debug("%s size is 0x%" PRIx64 "\n", filename, file_size);
186 if (file_size < opt_pad)
187 Fatal("%s is too small to be a valid kernel blob\n");
Bill Richardsona08b5c92010-06-30 21:59:43 -0700188
Bill Richardson31d95c22014-08-24 22:07:17 -0700189 Debug("Reading %s\n", filename);
190 fp = fopen(filename, "rb");
191 if (!fp)
192 Fatal("Unable to open file %s: %s\n", filename,
193 strerror(errno));
Bill Richardsona08b5c92010-06-30 21:59:43 -0700194
Bill Richardsonf318ee22014-09-23 14:30:30 -0700195 buf = malloc(file_size);
196 if (1 != fread(buf, file_size, 1, fp))
197 Fatal("Unable to read entirety of %s: %s\n", filename,
Bill Richardson31d95c22014-08-24 22:07:17 -0700198 error_fread(fp));
vbendebb2b0fcc2010-07-15 15:09:47 -0700199
Bill Richardson31d95c22014-08-24 22:07:17 -0700200 if (size_ptr)
Bill Richardsonf318ee22014-09-23 14:30:30 -0700201 *size_ptr = file_size;
Bill Richardson72e344d2012-03-19 12:47:18 -0700202
Bill Richardsonf318ee22014-09-23 14:30:30 -0700203 return buf;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700204}
205
Bill Richardson72e344d2012-03-19 12:47:18 -0700206/****************************************************************************/
Randall Spangler7d6898d2010-06-11 09:22:13 -0700207
Bill Richardson4dad6902014-12-03 16:13:33 -0800208static int do_vbutil_kernel(int argc, char *argv[])
Bill Richardson31d95c22014-08-24 22:07:17 -0700209{
210 char *filename = NULL;
211 char *oldfile = NULL;
212 char *keyblock_file = NULL;
213 char *signpubkey_file = NULL;
214 char *signprivkey_file = NULL;
215 char *version_str = NULL;
216 int version = -1;
217 char *vmlinuz_file = NULL;
218 char *bootloader_file = NULL;
219 char *config_file = NULL;
Shelley Chenf1f53b32015-01-08 09:13:44 -0800220 char *vmlinuz_out_file = NULL;
Bill Richardsone192e7f2014-09-23 12:49:26 -0700221 enum arch_t arch = ARCH_X86;
Bill Richardson31d95c22014-08-24 22:07:17 -0700222 uint64_t kernel_body_load_address = CROS_32BIT_ENTRY_ADDR;
223 int mode = 0;
224 int parse_error = 0;
225 uint64_t min_version = 0;
226 char *e;
Shelley Chenf1f53b32015-01-08 09:13:44 -0800227 int i = 0;
Bill Richardsonf318ee22014-09-23 14:30:30 -0700228 int rv;
229 VbKeyBlockHeader *keyblock = NULL;
230 VbKeyBlockHeader *t_keyblock = NULL;
Bill Richardson31d95c22014-08-24 22:07:17 -0700231 VbPrivateKey *signpriv_key = NULL;
232 VbPublicKey *signpub_key = NULL;
Bill Richardsonf318ee22014-09-23 14:30:30 -0700233 uint8_t *kpart_data = NULL;
234 uint64_t kpart_size = 0;
235 uint8_t *vmlinuz_buf = NULL;
236 uint64_t vmlinuz_size = 0;
237 uint8_t *t_config_data;
238 uint64_t t_config_size;
239 uint8_t *t_bootloader_data;
240 uint64_t t_bootloader_size;
Shelley Chenf1f53b32015-01-08 09:13:44 -0800241 uint64_t vmlinuz_header_size = 0;
242 uint64_t vmlinuz_header_address = 0;
Bill Richardsonf318ee22014-09-23 14:30:30 -0700243 VbKernelPreambleHeader *preamble = NULL;
244 uint8_t *kblob_data = NULL;
245 uint64_t kblob_size = 0;
246 uint8_t *vblock_data = NULL;
247 uint64_t vblock_size = 0;
Shelley Chenf1f53b32015-01-08 09:13:44 -0800248 FILE *f;
Bill Richardson72e344d2012-03-19 12:47:18 -0700249
Bill Richardson31d95c22014-08-24 22:07:17 -0700250 while (((i = getopt_long(argc, argv, ":", long_opts, NULL)) != -1) &&
251 !parse_error) {
252 switch (i) {
253 default:
254 case '?':
255 /* Unhandled option */
256 parse_error = 1;
257 break;
Bill Richardson72e344d2012-03-19 12:47:18 -0700258
Bill Richardson31d95c22014-08-24 22:07:17 -0700259 case 0:
260 /* silently handled option */
261 break;
Bill Richardson72e344d2012-03-19 12:47:18 -0700262
Bill Richardson31d95c22014-08-24 22:07:17 -0700263 case OPT_MODE_PACK:
264 case OPT_MODE_REPACK:
265 case OPT_MODE_VERIFY:
Shelley Chenf1f53b32015-01-08 09:13:44 -0800266 case OPT_MODE_GET_VMLINUZ:
Bill Richardson31d95c22014-08-24 22:07:17 -0700267 if (mode && (mode != i)) {
268 fprintf(stderr,
269 "Only one mode can be specified\n");
270 parse_error = 1;
271 break;
272 }
273 mode = i;
274 filename = optarg;
275 break;
Bill Richardson72e344d2012-03-19 12:47:18 -0700276
Bill Richardson31d95c22014-08-24 22:07:17 -0700277 case OPT_ARCH:
278 /* check the first 3 characters to also detect x86_64 */
279 if ((!strncasecmp(optarg, "x86", 3)) ||
280 (!strcasecmp(optarg, "amd64")))
281 arch = ARCH_X86;
282 else if ((!strcasecmp(optarg, "arm")) ||
283 (!strcasecmp(optarg, "aarch64")))
284 arch = ARCH_ARM;
285 else if (!strcasecmp(optarg, "mips"))
286 arch = ARCH_MIPS;
287 else {
288 fprintf(stderr,
289 "Unknown architecture string: %s\n",
290 optarg);
291 parse_error = 1;
292 }
293 break;
Bill Richardson72e344d2012-03-19 12:47:18 -0700294
Bill Richardson31d95c22014-08-24 22:07:17 -0700295 case OPT_OLDBLOB:
296 oldfile = optarg;
297 break;
Bill Richardson72e344d2012-03-19 12:47:18 -0700298
Bill Richardson31d95c22014-08-24 22:07:17 -0700299 case OPT_KLOADADDR:
Bill Richardson31d95c22014-08-24 22:07:17 -0700300 kernel_body_load_address = strtoul(optarg, &e, 0);
301 if (!*optarg || (e && *e)) {
302 fprintf(stderr, "Invalid --kloadaddr\n");
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_KEYBLOCK:
308 keyblock_file = optarg;
309 break;
Bill Richardson72e344d2012-03-19 12:47:18 -0700310
Bill Richardson31d95c22014-08-24 22:07:17 -0700311 case OPT_SIGNPUBKEY:
312 signpubkey_file = optarg;
313 break;
Bill Richardson72e344d2012-03-19 12:47:18 -0700314
Bill Richardson31d95c22014-08-24 22:07:17 -0700315 case OPT_SIGNPRIVATE:
316 signprivkey_file = optarg;
317 break;
Bill Richardson72e344d2012-03-19 12:47:18 -0700318
Bill Richardson31d95c22014-08-24 22:07:17 -0700319 case OPT_VMLINUZ:
320 vmlinuz_file = optarg;
321 break;
Bill Richardson72e344d2012-03-19 12:47:18 -0700322
Bill Richardson31d95c22014-08-24 22:07:17 -0700323 case OPT_BOOTLOADER:
324 bootloader_file = optarg;
325 break;
Bill Richardson72e344d2012-03-19 12:47:18 -0700326
Bill Richardson31d95c22014-08-24 22:07:17 -0700327 case OPT_CONFIG:
328 config_file = optarg;
329 break;
Bill Richardson72e344d2012-03-19 12:47:18 -0700330
Bill Richardson31d95c22014-08-24 22:07:17 -0700331 case OPT_VBLOCKONLY:
332 opt_vblockonly = 1;
333 break;
Bill Richardson72e344d2012-03-19 12:47:18 -0700334
Bill Richardson31d95c22014-08-24 22:07:17 -0700335 case OPT_VERSION:
336 version_str = optarg;
337 version = strtoul(optarg, &e, 0);
338 if (!*optarg || (e && *e)) {
339 fprintf(stderr, "Invalid --version\n");
340 parse_error = 1;
341 }
342 break;
Bill Richardson72e344d2012-03-19 12:47:18 -0700343
Bill Richardson31d95c22014-08-24 22:07:17 -0700344 case OPT_MINVERSION:
345 min_version = strtoul(optarg, &e, 0);
346 if (!*optarg || (e && *e)) {
347 fprintf(stderr, "Invalid --minversion\n");
348 parse_error = 1;
349 }
350 break;
Bill Richardson72e344d2012-03-19 12:47:18 -0700351
Bill Richardson31d95c22014-08-24 22:07:17 -0700352 case OPT_PAD:
353 opt_pad = strtoul(optarg, &e, 0);
354 if (!*optarg || (e && *e)) {
355 fprintf(stderr, "Invalid --pad\n");
356 parse_error = 1;
357 }
358 break;
Shelley Chenf1f53b32015-01-08 09:13:44 -0800359 case OPT_VMLINUZ_OUT:
360 vmlinuz_out_file = optarg;
Bill Richardson31d95c22014-08-24 22:07:17 -0700361 }
362 }
Bill Richardson72e344d2012-03-19 12:47:18 -0700363
Bill Richardson779796f2014-09-23 11:47:40 -0700364 if (parse_error) {
365 print_help(argv[0]);
366 return 1;
367 }
Bill Richardson72e344d2012-03-19 12:47:18 -0700368
Bill Richardson31d95c22014-08-24 22:07:17 -0700369 switch (mode) {
370 case OPT_MODE_PACK:
Bill Richardson72e344d2012-03-19 12:47:18 -0700371
Bill Richardson31d95c22014-08-24 22:07:17 -0700372 if (!keyblock_file)
373 Fatal("Missing required keyblock file.\n");
Bill Richardson72e344d2012-03-19 12:47:18 -0700374
Bill Richardsonf318ee22014-09-23 14:30:30 -0700375 t_keyblock = (VbKeyBlockHeader *)ReadFile(keyblock_file, 0);
376 if (!t_keyblock)
Bill Richardson31d95c22014-08-24 22:07:17 -0700377 Fatal("Error reading key block.\n");
Bill Richardson72e344d2012-03-19 12:47:18 -0700378
Bill Richardson31d95c22014-08-24 22:07:17 -0700379 if (!signprivkey_file)
380 Fatal("Missing required signprivate file.\n");
Bill Richardson72e344d2012-03-19 12:47:18 -0700381
Bill Richardson31d95c22014-08-24 22:07:17 -0700382 signpriv_key = PrivateKeyRead(signprivkey_file);
383 if (!signpriv_key)
384 Fatal("Error reading signing key.\n");
Bill Richardson72e344d2012-03-19 12:47:18 -0700385
Bill Richardsonf318ee22014-09-23 14:30:30 -0700386 if (!config_file)
387 Fatal("Missing required config file.\n");
Bill Richardson72e344d2012-03-19 12:47:18 -0700388
Bill Richardsonf318ee22014-09-23 14:30:30 -0700389 Debug("Reading %s\n", config_file);
390 t_config_data =
391 ReadConfigFile(config_file, &t_config_size);
392 if (!t_config_data)
393 Fatal("Error reading config file.\n");
Bill Richardson72e344d2012-03-19 12:47:18 -0700394
Bill Richardsonf318ee22014-09-23 14:30:30 -0700395 if (!bootloader_file)
396 Fatal("Missing required bootloader file.\n");
Bill Richardson72e344d2012-03-19 12:47:18 -0700397
Bill Richardsonf318ee22014-09-23 14:30:30 -0700398 Debug("Reading %s\n", bootloader_file);
399 t_bootloader_data = ReadFile(bootloader_file,
400 &t_bootloader_size);
401 if (!t_bootloader_data)
402 Fatal("Error reading bootloader file.\n");
403 Debug(" bootloader file size=0x%" PRIx64 "\n",
404 t_bootloader_size);
Bill Richardson72e344d2012-03-19 12:47:18 -0700405
Bill Richardsonf318ee22014-09-23 14:30:30 -0700406 if (!vmlinuz_file)
407 Fatal("Missing required vmlinuz file.\n");
408 Debug("Reading %s\n", vmlinuz_file);
409 vmlinuz_buf = ReadFile(vmlinuz_file, &vmlinuz_size);
410 if (!vmlinuz_buf)
411 Fatal("Error reading vmlinuz file.\n");
412 Debug(" vmlinuz file size=0x%" PRIx64 "\n",
413 vmlinuz_size);
414 if (!vmlinuz_size)
415 Fatal("Empty vmlinuz file\n");
Bill Richardson31d95c22014-08-24 22:07:17 -0700416
Bill Richardsonf318ee22014-09-23 14:30:30 -0700417 kblob_data = CreateKernelBlob(
418 vmlinuz_buf, vmlinuz_size,
419 arch, kernel_body_load_address,
420 t_config_data, t_config_size,
421 t_bootloader_data, t_bootloader_size,
422 &kblob_size);
423 if (!kblob_data)
424 Fatal("Unable to create kernel blob\n");
Bill Richardson31d95c22014-08-24 22:07:17 -0700425
Bill Richardsonf318ee22014-09-23 14:30:30 -0700426 Debug("kblob_size = 0x%" PRIx64 "\n", kblob_size);
427
428 vblock_data = SignKernelBlob(kblob_data, kblob_size, opt_pad,
429 version, kernel_body_load_address,
430 t_keyblock, signpriv_key,
431 &vblock_size);
432 if (!vblock_data)
433 Fatal("Unable to sign kernel blob\n");
434
435 Debug("vblock_size = 0x%" PRIx64 "\n", vblock_size);
436
437 if (opt_vblockonly)
438 rv = WriteSomeParts(filename,
439 vblock_data, vblock_size,
440 NULL, 0);
441 else
442 rv = WriteSomeParts(filename,
443 vblock_data, vblock_size,
444 kblob_data, kblob_size);
445 return rv;
Bill Richardson31d95c22014-08-24 22:07:17 -0700446
447 case OPT_MODE_REPACK:
448
449 /* Required */
450
451 if (!signprivkey_file)
452 Fatal("Missing required signprivate file.\n");
453
454 signpriv_key = PrivateKeyRead(signprivkey_file);
455 if (!signpriv_key)
456 Fatal("Error reading signing key.\n");
457
458 if (!oldfile)
459 Fatal("Missing previously packed blob.\n");
460
Bill Richardsonf318ee22014-09-23 14:30:30 -0700461 /* Load the kernel partition */
462 kpart_data = ReadOldKPartFromFileOrDie(oldfile, &kpart_size);
Bill Richardson31d95c22014-08-24 22:07:17 -0700463
Bill Richardsonf318ee22014-09-23 14:30:30 -0700464 kblob_data = UnpackKPart(kpart_data, kpart_size, opt_pad,
465 &keyblock, &preamble, &kblob_size);
Bill Richardson31d95c22014-08-24 22:07:17 -0700466
Bill Richardsonf318ee22014-09-23 14:30:30 -0700467 if (!kblob_data)
468 Fatal("Unable to unpack kernel partition\n");
Bill Richardson31d95c22014-08-24 22:07:17 -0700469
Bill Richardsonf318ee22014-09-23 14:30:30 -0700470 kernel_body_load_address = preamble->body_load_address;
Bill Richardson31d95c22014-08-24 22:07:17 -0700471
Bill Richardsonf318ee22014-09-23 14:30:30 -0700472 /* Update the config if asked */
Bill Richardson31d95c22014-08-24 22:07:17 -0700473 if (config_file) {
Bill Richardson31d95c22014-08-24 22:07:17 -0700474 Debug("Reading %s\n", config_file);
Bill Richardsonf318ee22014-09-23 14:30:30 -0700475 t_config_data =
476 ReadConfigFile(config_file, &t_config_size);
477 if (!t_config_data)
Bill Richardson31d95c22014-08-24 22:07:17 -0700478 Fatal("Error reading config file.\n");
Bill Richardsonf318ee22014-09-23 14:30:30 -0700479 if (0 != UpdateKernelBlobConfig(
480 kblob_data, kblob_size,
481 t_config_data, t_config_size))
482 Fatal("Unable to update config\n");
Bill Richardson31d95c22014-08-24 22:07:17 -0700483 }
484
Bill Richardsonf318ee22014-09-23 14:30:30 -0700485 if (!version_str)
486 version = preamble->kernel_version;
487
Bill Richardson31d95c22014-08-24 22:07:17 -0700488 if (keyblock_file) {
Bill Richardsonf318ee22014-09-23 14:30:30 -0700489 t_keyblock =
490 (VbKeyBlockHeader *)ReadFile(keyblock_file, 0);
491 if (!t_keyblock)
Bill Richardson31d95c22014-08-24 22:07:17 -0700492 Fatal("Error reading key block.\n");
493 }
494
Bill Richardsonf1dba022014-10-01 14:10:45 -0700495 /* Reuse previous body size */
Bill Richardsonf318ee22014-09-23 14:30:30 -0700496 vblock_data = SignKernelBlob(kblob_data, kblob_size, opt_pad,
497 version, kernel_body_load_address,
498 t_keyblock ? t_keyblock : keyblock,
499 signpriv_key, &vblock_size);
500 if (!vblock_data)
501 Fatal("Unable to sign kernel blob\n");
Bill Richardson31d95c22014-08-24 22:07:17 -0700502
Bill Richardsonf318ee22014-09-23 14:30:30 -0700503 if (opt_vblockonly)
504 rv = WriteSomeParts(filename,
505 vblock_data, vblock_size,
506 NULL, 0);
507 else
508 rv = WriteSomeParts(filename,
509 vblock_data, vblock_size,
510 kblob_data, kblob_size);
511 return rv;
Bill Richardson31d95c22014-08-24 22:07:17 -0700512
513 case OPT_MODE_VERIFY:
514
515 /* Optional */
516
517 if (signpubkey_file) {
518 signpub_key = PublicKeyRead(signpubkey_file);
519 if (!signpub_key)
520 Fatal("Error reading public key.\n");
521 }
522
523 /* Do it */
524
Bill Richardsonf318ee22014-09-23 14:30:30 -0700525 /* Load the kernel partition */
526 kpart_data = ReadOldKPartFromFileOrDie(filename, &kpart_size);
Bill Richardson31d95c22014-08-24 22:07:17 -0700527
Bill Richardsonf318ee22014-09-23 14:30:30 -0700528 kblob_data = UnpackKPart(kpart_data, kpart_size, opt_pad,
529 0, 0, &kblob_size);
530 if (!kblob_data)
531 Fatal("Unable to unpack kernel partition\n");
532
533 rv = VerifyKernelBlob(kblob_data, kblob_size,
534 signpub_key, keyblock_file, min_version);
535
536 return rv;
Shelley Chenf1f53b32015-01-08 09:13:44 -0800537
538 case OPT_MODE_GET_VMLINUZ:
539
540 if (!vmlinuz_out_file) {
541 fprintf(stderr,
542 "USE: vbutil_kernel --get-vmlinuz <file> "
543 "--vmlinuz-out <file>\n");
544 print_help(argv[0]);
545 return 1;
546 }
547
548 kpart_data = ReadOldKPartFromFileOrDie(filename, &kpart_size);
549
550 kblob_data = UnpackKPart(kpart_data, kpart_size, opt_pad,
551 &keyblock, &preamble, &kblob_size);
552
553 if (!kblob_data)
554 Fatal("Unable to unpack kernel partition\n");
555
556 f = fopen(vmlinuz_out_file, "wb");
557 if (!f) {
558 VbExError("Can't open output file %s\n",
559 vmlinuz_out_file);
560 return 1;
561 }
562
563 /* Now stick 16-bit header followed by kernel block into
564 output */
565 if (VbGetKernelVmlinuzHeader(preamble,
566 &vmlinuz_header_address,
567 &vmlinuz_header_size)
568 != VBOOT_SUCCESS) {
569 Fatal("Unable to retrieve Vmlinuz Header!");
570 }
571 if (vmlinuz_header_size) {
572 // verify that the 16-bit header is included in the
573 // kblob (to make sure that it's included in the
574 // signature)
575 if (VerifyVmlinuzInsideKBlob(preamble->body_load_address,
576 kblob_size,
577 vmlinuz_header_address,
578 vmlinuz_header_size)) {
579 VbExError("Vmlinuz header not signed!\n");
580 fclose(f);
581 unlink(vmlinuz_out_file);
582 return 1;
583 }
584
585 i = (1 != fwrite((void*)(uintptr_t)
586 vmlinuz_header_address,
587 vmlinuz_header_size,
588 1,
589 f));
590 }
591 i = i || (1 != fwrite(kblob_data,
592 kblob_size,
593 1,
594 f));
595 if (i) {
596 VbExError("Can't write output file %s\n",
597 vmlinuz_out_file);
598 fclose(f);
599 unlink(vmlinuz_out_file);
600 return 1;
601 }
602
603 fclose(f);
604 return 1;
Bill Richardson31d95c22014-08-24 22:07:17 -0700605 }
606
607 fprintf(stderr,
Shelley Chenf1f53b32015-01-08 09:13:44 -0800608 "You must specify a mode: "
609 "--pack, --repack, --verify, or --get-vmlinuz\n");
Bill Richardson779796f2014-09-23 11:47:40 -0700610 print_help(argv[0]);
611 return 1;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700612}
Bill Richardson6f396152014-07-15 12:52:19 -0700613
Bill Richardson4dad6902014-12-03 16:13:33 -0800614DECLARE_FUTIL_COMMAND(vbutil_kernel, do_vbutil_kernel,
Bill Richardsonf318ee22014-09-23 14:30:30 -0700615 "Creates, signs, and verifies the kernel partition",
Bill Richardson779796f2014-09-23 11:47:40 -0700616 print_help);