blob: ae4fd3f9ce38882799fb7a684f2930923ee513ae [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,
Randall Spangler7d6898d2010-06-11 09:22:13 -070066};
67
Mike Frysinger7351ed72014-08-18 10:47:42 -040068static const struct option long_opts[] = {
Bill Richardson31d95c22014-08-24 22:07:17 -070069 {"pack", 1, 0, OPT_MODE_PACK},
70 {"repack", 1, 0, OPT_MODE_REPACK},
71 {"verify", 1, 0, OPT_MODE_VERIFY},
Shelley Chenf1f53b32015-01-08 09:13:44 -080072 {"get-vmlinuz", 1, 0, OPT_MODE_GET_VMLINUZ},
Bill Richardson31d95c22014-08-24 22:07:17 -070073 {"arch", 1, 0, OPT_ARCH},
74 {"oldblob", 1, 0, OPT_OLDBLOB},
75 {"kloadaddr", 1, 0, OPT_KLOADADDR},
76 {"keyblock", 1, 0, OPT_KEYBLOCK},
77 {"signpubkey", 1, 0, OPT_SIGNPUBKEY},
78 {"signprivate", 1, 0, OPT_SIGNPRIVATE},
79 {"version", 1, 0, OPT_VERSION},
80 {"minversion", 1, 0, OPT_MINVERSION},
81 {"vmlinuz", 1, 0, OPT_VMLINUZ},
82 {"bootloader", 1, 0, OPT_BOOTLOADER},
83 {"config", 1, 0, OPT_CONFIG},
84 {"vblockonly", 0, 0, OPT_VBLOCKONLY},
85 {"pad", 1, 0, OPT_PAD},
86 {"verbose", 0, &opt_verbose, 1},
Bill Richardsone192e7f2014-09-23 12:49:26 -070087 {"debug", 0, &debugging_enabled, 1},
Shelley Chenf1f53b32015-01-08 09:13:44 -080088 {"vmlinuz-out", 1, 0, OPT_VMLINUZ_OUT},
Bill Richardson31d95c22014-08-24 22:07:17 -070089 {NULL, 0, 0, 0}
Randall Spangler7d6898d2010-06-11 09:22:13 -070090};
91
92
Bill Richardson31d95c22014-08-24 22:07:17 -070093
94static const char usage[] =
Bill Richardson31d95c22014-08-24 22:07:17 -070095 "\n"
Bill Richardson779796f2014-09-23 11:47:40 -070096 "Usage: " MYNAME " %s --pack <file> [PARAMETERS]\n"
Bill Richardson31d95c22014-08-24 22:07:17 -070097 "\n"
98 " Required parameters:\n"
99 " --keyblock <file> Key block in .keyblock format\n"
100 " --signprivate <file> Private key to sign kernel data,\n"
101 " in .vbprivk format\n"
102 " --version <number> Kernel version\n"
103 " --vmlinuz <file> Linux kernel bzImage file\n"
104 " --bootloader <file> Bootloader stub\n"
105 " --config <file> Command line file\n"
106 " --arch <arch> Cpu architecture (default x86)\n"
107 "\n"
108 " Optional:\n"
109 " --kloadaddr <address> Assign kernel body load address\n"
110 " --pad <number> Verification padding size in bytes\n"
111 " --vblockonly Emit just the verification blob\n"
112 "\nOR\n\n"
Bill Richardson779796f2014-09-23 11:47:40 -0700113 "Usage: " MYNAME " %s --repack <file> [PARAMETERS]\n"
Bill Richardson31d95c22014-08-24 22:07:17 -0700114 "\n"
115 " Required parameters:\n"
116 " --signprivate <file> Private key to sign kernel data,\n"
117 " in .vbprivk format\n"
118 " --oldblob <file> Previously packed kernel blob\n"
119 " (including verfication blob)\n"
120 "\n"
121 " Optional:\n"
122 " --keyblock <file> Key block in .keyblock format\n"
123 " --config <file> New command line file\n"
124 " --version <number> Kernel version\n"
125 " --kloadaddr <address> Assign kernel body load address\n"
126 " --pad <number> Verification blob size in bytes\n"
127 " --vblockonly Emit just the verification blob\n"
128 "\nOR\n\n"
Bill Richardson779796f2014-09-23 11:47:40 -0700129 "Usage: " MYNAME " %s --verify <file> [PARAMETERS]\n"
Bill Richardson31d95c22014-08-24 22:07:17 -0700130 "\n"
131 " Optional:\n"
132 " --signpubkey <file>"
133 " Public key to verify kernel keyblock,\n"
134 " in .vbpubk format\n"
135 " --verbose Print a more detailed report\n"
136 " --keyblock <file> Outputs the verified key block,\n"
137 " in .keyblock format\n"
138 " --pad <number> Verification padding size in bytes\n"
139 " --minversion <number> Minimum combined kernel key version\n"
Shelley Chenf1f53b32015-01-08 09:13:44 -0800140 "\nOR\n\n"
141 "Usage: " MYNAME " %s --get-vmlinuz <file> [PARAMETERS]\n"
142 "\n"
143 " Required parameters:\n"
144 " --vmlinuz-out <file> vmlinuz image output file\n"
Bill Richardson31d95c22014-08-24 22:07:17 -0700145 "\n";
146
147
Randall Spangler7d6898d2010-06-11 09:22:13 -0700148/* Print help and return error */
Bill Richardson779796f2014-09-23 11:47:40 -0700149static void print_help(const char *progname)
Bill Richardson31d95c22014-08-24 22:07:17 -0700150{
Shelley Chenf1f53b32015-01-08 09:13:44 -0800151 printf(usage, progname, progname, progname, progname);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700152}
153
Bill Richardson72e344d2012-03-19 12:47:18 -0700154
Bill Richardson2f6a71f2010-10-14 09:25:39 -0700155/* Return an explanation when fread() fails. */
Bill Richardson779796f2014-09-23 11:47:40 -0700156static const char *error_fread(FILE *fp)
Bill Richardson31d95c22014-08-24 22:07:17 -0700157{
158 const char *retval = "beats me why";
159 if (feof(fp))
160 retval = "EOF";
161 else if (ferror(fp))
162 retval = strerror(errno);
163 clearerr(fp);
164 return retval;
Bill Richardson2f6a71f2010-10-14 09:25:39 -0700165}
Randall Spangler7d6898d2010-06-11 09:22:13 -0700166
Randall Spangler7d6898d2010-06-11 09:22:13 -0700167
Bill Richardsonf318ee22014-09-23 14:30:30 -0700168/* This reads a complete kernel partition into a buffer */
169static uint8_t *ReadOldKPartFromFileOrDie(const char *filename,
Bill Richardson779796f2014-09-23 11:47:40 -0700170 uint64_t *size_ptr)
Bill Richardson31d95c22014-08-24 22:07:17 -0700171{
172 FILE *fp = NULL;
173 struct stat statbuf;
Bill Richardson31d95c22014-08-24 22:07:17 -0700174 uint8_t *buf;
Bill Richardson31d95c22014-08-24 22:07:17 -0700175 uint64_t file_size = 0;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700176
Bill Richardson31d95c22014-08-24 22:07:17 -0700177 if (0 != stat(filename, &statbuf))
178 Fatal("Unable to stat %s: %s\n", filename, strerror(errno));
Bill Richardsona08b5c92010-06-30 21:59:43 -0700179
Bill Richardson31d95c22014-08-24 22:07:17 -0700180 if (S_ISBLK(statbuf.st_mode)) {
David Riley05987b12015-02-05 19:22:49 -0800181#ifndef HAVE_MACOS
Bill Richardson779796f2014-09-23 11:47:40 -0700182 int fd = open(filename, O_RDONLY);
183 if (fd >= 0) {
Bill Richardson31d95c22014-08-24 22:07:17 -0700184 ioctl(fd, BLKGETSIZE64, &file_size);
185 close(fd);
186 }
David Riley05987b12015-02-05 19:22:49 -0800187#endif
Bill Richardson31d95c22014-08-24 22:07:17 -0700188 } else {
189 file_size = statbuf.st_size;
190 }
191 Debug("%s size is 0x%" PRIx64 "\n", filename, file_size);
192 if (file_size < opt_pad)
193 Fatal("%s is too small to be a valid kernel blob\n");
Bill Richardsona08b5c92010-06-30 21:59:43 -0700194
Bill Richardson31d95c22014-08-24 22:07:17 -0700195 Debug("Reading %s\n", filename);
196 fp = fopen(filename, "rb");
197 if (!fp)
198 Fatal("Unable to open file %s: %s\n", filename,
199 strerror(errno));
Bill Richardsona08b5c92010-06-30 21:59:43 -0700200
Bill Richardsonf318ee22014-09-23 14:30:30 -0700201 buf = malloc(file_size);
202 if (1 != fread(buf, file_size, 1, fp))
203 Fatal("Unable to read entirety of %s: %s\n", filename,
Bill Richardson31d95c22014-08-24 22:07:17 -0700204 error_fread(fp));
vbendebb2b0fcc2010-07-15 15:09:47 -0700205
Bill Richardson31d95c22014-08-24 22:07:17 -0700206 if (size_ptr)
Bill Richardsonf318ee22014-09-23 14:30:30 -0700207 *size_ptr = file_size;
Bill Richardson72e344d2012-03-19 12:47:18 -0700208
Bill Richardsonf318ee22014-09-23 14:30:30 -0700209 return buf;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700210}
211
Bill Richardson72e344d2012-03-19 12:47:18 -0700212/****************************************************************************/
Randall Spangler7d6898d2010-06-11 09:22:13 -0700213
Bill Richardson4dad6902014-12-03 16:13:33 -0800214static int do_vbutil_kernel(int argc, char *argv[])
Bill Richardson31d95c22014-08-24 22:07:17 -0700215{
216 char *filename = NULL;
217 char *oldfile = NULL;
218 char *keyblock_file = NULL;
219 char *signpubkey_file = NULL;
220 char *signprivkey_file = NULL;
221 char *version_str = NULL;
222 int version = -1;
223 char *vmlinuz_file = NULL;
224 char *bootloader_file = NULL;
225 char *config_file = NULL;
Shelley Chenf1f53b32015-01-08 09:13:44 -0800226 char *vmlinuz_out_file = NULL;
Bill Richardsone192e7f2014-09-23 12:49:26 -0700227 enum arch_t arch = ARCH_X86;
Bill Richardson31d95c22014-08-24 22:07:17 -0700228 uint64_t kernel_body_load_address = CROS_32BIT_ENTRY_ADDR;
229 int mode = 0;
230 int parse_error = 0;
231 uint64_t min_version = 0;
232 char *e;
Shelley Chenf1f53b32015-01-08 09:13:44 -0800233 int i = 0;
Shelley Chen1bdc6122015-02-02 10:06:10 -0800234 int errcount = 0;
Bill Richardsonf318ee22014-09-23 14:30:30 -0700235 int rv;
236 VbKeyBlockHeader *keyblock = NULL;
237 VbKeyBlockHeader *t_keyblock = NULL;
Bill Richardson31d95c22014-08-24 22:07:17 -0700238 VbPrivateKey *signpriv_key = NULL;
239 VbPublicKey *signpub_key = NULL;
Bill Richardsonf318ee22014-09-23 14:30:30 -0700240 uint8_t *kpart_data = NULL;
241 uint64_t kpart_size = 0;
242 uint8_t *vmlinuz_buf = NULL;
243 uint64_t vmlinuz_size = 0;
244 uint8_t *t_config_data;
245 uint64_t t_config_size;
246 uint8_t *t_bootloader_data;
247 uint64_t t_bootloader_size;
Shelley Chenf1f53b32015-01-08 09:13:44 -0800248 uint64_t vmlinuz_header_size = 0;
249 uint64_t vmlinuz_header_address = 0;
Shelley Chen1bdc6122015-02-02 10:06:10 -0800250 uint64_t vmlinuz_header_offset = 0;
Bill Richardsonf318ee22014-09-23 14:30:30 -0700251 VbKernelPreambleHeader *preamble = NULL;
252 uint8_t *kblob_data = NULL;
253 uint64_t kblob_size = 0;
254 uint8_t *vblock_data = NULL;
255 uint64_t vblock_size = 0;
Shelley Chenf1f53b32015-01-08 09:13:44 -0800256 FILE *f;
Bill Richardson72e344d2012-03-19 12:47:18 -0700257
Bill Richardson31d95c22014-08-24 22:07:17 -0700258 while (((i = getopt_long(argc, argv, ":", long_opts, NULL)) != -1) &&
259 !parse_error) {
260 switch (i) {
261 default:
262 case '?':
263 /* Unhandled option */
264 parse_error = 1;
265 break;
Bill Richardson72e344d2012-03-19 12:47:18 -0700266
Bill Richardson31d95c22014-08-24 22:07:17 -0700267 case 0:
268 /* silently handled option */
269 break;
Bill Richardson72e344d2012-03-19 12:47:18 -0700270
Bill Richardson31d95c22014-08-24 22:07:17 -0700271 case OPT_MODE_PACK:
272 case OPT_MODE_REPACK:
273 case OPT_MODE_VERIFY:
Shelley Chenf1f53b32015-01-08 09:13:44 -0800274 case OPT_MODE_GET_VMLINUZ:
Bill Richardson31d95c22014-08-24 22:07:17 -0700275 if (mode && (mode != i)) {
276 fprintf(stderr,
277 "Only one mode can be specified\n");
278 parse_error = 1;
279 break;
280 }
281 mode = i;
282 filename = optarg;
283 break;
Bill Richardson72e344d2012-03-19 12:47:18 -0700284
Bill Richardson31d95c22014-08-24 22:07:17 -0700285 case OPT_ARCH:
286 /* check the first 3 characters to also detect x86_64 */
287 if ((!strncasecmp(optarg, "x86", 3)) ||
288 (!strcasecmp(optarg, "amd64")))
289 arch = ARCH_X86;
290 else if ((!strcasecmp(optarg, "arm")) ||
291 (!strcasecmp(optarg, "aarch64")))
292 arch = ARCH_ARM;
293 else if (!strcasecmp(optarg, "mips"))
294 arch = ARCH_MIPS;
295 else {
296 fprintf(stderr,
297 "Unknown architecture string: %s\n",
298 optarg);
299 parse_error = 1;
300 }
301 break;
Bill Richardson72e344d2012-03-19 12:47:18 -0700302
Bill Richardson31d95c22014-08-24 22:07:17 -0700303 case OPT_OLDBLOB:
304 oldfile = optarg;
305 break;
Bill Richardson72e344d2012-03-19 12:47:18 -0700306
Bill Richardson31d95c22014-08-24 22:07:17 -0700307 case OPT_KLOADADDR:
Bill Richardson31d95c22014-08-24 22:07:17 -0700308 kernel_body_load_address = strtoul(optarg, &e, 0);
309 if (!*optarg || (e && *e)) {
310 fprintf(stderr, "Invalid --kloadaddr\n");
311 parse_error = 1;
312 }
313 break;
Bill Richardson72e344d2012-03-19 12:47:18 -0700314
Bill Richardson31d95c22014-08-24 22:07:17 -0700315 case OPT_KEYBLOCK:
316 keyblock_file = optarg;
317 break;
Bill Richardson72e344d2012-03-19 12:47:18 -0700318
Bill Richardson31d95c22014-08-24 22:07:17 -0700319 case OPT_SIGNPUBKEY:
320 signpubkey_file = optarg;
321 break;
Bill Richardson72e344d2012-03-19 12:47:18 -0700322
Bill Richardson31d95c22014-08-24 22:07:17 -0700323 case OPT_SIGNPRIVATE:
324 signprivkey_file = optarg;
325 break;
Bill Richardson72e344d2012-03-19 12:47:18 -0700326
Bill Richardson31d95c22014-08-24 22:07:17 -0700327 case OPT_VMLINUZ:
328 vmlinuz_file = optarg;
329 break;
Bill Richardson72e344d2012-03-19 12:47:18 -0700330
Bill Richardson31d95c22014-08-24 22:07:17 -0700331 case OPT_BOOTLOADER:
332 bootloader_file = optarg;
333 break;
Bill Richardson72e344d2012-03-19 12:47:18 -0700334
Bill Richardson31d95c22014-08-24 22:07:17 -0700335 case OPT_CONFIG:
336 config_file = optarg;
337 break;
Bill Richardson72e344d2012-03-19 12:47:18 -0700338
Bill Richardson31d95c22014-08-24 22:07:17 -0700339 case OPT_VBLOCKONLY:
340 opt_vblockonly = 1;
341 break;
Bill Richardson72e344d2012-03-19 12:47:18 -0700342
Bill Richardson31d95c22014-08-24 22:07:17 -0700343 case OPT_VERSION:
344 version_str = optarg;
345 version = strtoul(optarg, &e, 0);
346 if (!*optarg || (e && *e)) {
347 fprintf(stderr, "Invalid --version\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_MINVERSION:
353 min_version = strtoul(optarg, &e, 0);
354 if (!*optarg || (e && *e)) {
355 fprintf(stderr, "Invalid --minversion\n");
356 parse_error = 1;
357 }
358 break;
Bill Richardson72e344d2012-03-19 12:47:18 -0700359
Bill Richardson31d95c22014-08-24 22:07:17 -0700360 case OPT_PAD:
361 opt_pad = strtoul(optarg, &e, 0);
362 if (!*optarg || (e && *e)) {
363 fprintf(stderr, "Invalid --pad\n");
364 parse_error = 1;
365 }
366 break;
Shelley Chenf1f53b32015-01-08 09:13:44 -0800367 case OPT_VMLINUZ_OUT:
368 vmlinuz_out_file = optarg;
Bill Richardson31d95c22014-08-24 22:07:17 -0700369 }
370 }
Bill Richardson72e344d2012-03-19 12:47:18 -0700371
Bill Richardson779796f2014-09-23 11:47:40 -0700372 if (parse_error) {
373 print_help(argv[0]);
374 return 1;
375 }
Bill Richardson72e344d2012-03-19 12:47:18 -0700376
Bill Richardson31d95c22014-08-24 22:07:17 -0700377 switch (mode) {
378 case OPT_MODE_PACK:
Bill Richardson72e344d2012-03-19 12:47:18 -0700379
Bill Richardson31d95c22014-08-24 22:07:17 -0700380 if (!keyblock_file)
381 Fatal("Missing required keyblock file.\n");
Bill Richardson72e344d2012-03-19 12:47:18 -0700382
Bill Richardsonf318ee22014-09-23 14:30:30 -0700383 t_keyblock = (VbKeyBlockHeader *)ReadFile(keyblock_file, 0);
384 if (!t_keyblock)
Bill Richardson31d95c22014-08-24 22:07:17 -0700385 Fatal("Error reading key block.\n");
Bill Richardson72e344d2012-03-19 12:47:18 -0700386
Bill Richardson31d95c22014-08-24 22:07:17 -0700387 if (!signprivkey_file)
388 Fatal("Missing required signprivate file.\n");
Bill Richardson72e344d2012-03-19 12:47:18 -0700389
Bill Richardson31d95c22014-08-24 22:07:17 -0700390 signpriv_key = PrivateKeyRead(signprivkey_file);
391 if (!signpriv_key)
392 Fatal("Error reading signing key.\n");
Bill Richardson72e344d2012-03-19 12:47:18 -0700393
Bill Richardsonf318ee22014-09-23 14:30:30 -0700394 if (!config_file)
395 Fatal("Missing required config file.\n");
Bill Richardson72e344d2012-03-19 12:47:18 -0700396
Bill Richardsonf318ee22014-09-23 14:30:30 -0700397 Debug("Reading %s\n", config_file);
398 t_config_data =
399 ReadConfigFile(config_file, &t_config_size);
400 if (!t_config_data)
401 Fatal("Error reading config file.\n");
Bill Richardson72e344d2012-03-19 12:47:18 -0700402
Bill Richardsonf318ee22014-09-23 14:30:30 -0700403 if (!bootloader_file)
404 Fatal("Missing required bootloader file.\n");
Bill Richardson72e344d2012-03-19 12:47:18 -0700405
Bill Richardsonf318ee22014-09-23 14:30:30 -0700406 Debug("Reading %s\n", bootloader_file);
407 t_bootloader_data = ReadFile(bootloader_file,
408 &t_bootloader_size);
409 if (!t_bootloader_data)
410 Fatal("Error reading bootloader file.\n");
411 Debug(" bootloader file size=0x%" PRIx64 "\n",
412 t_bootloader_size);
Bill Richardson72e344d2012-03-19 12:47:18 -0700413
Bill Richardsonf318ee22014-09-23 14:30:30 -0700414 if (!vmlinuz_file)
415 Fatal("Missing required vmlinuz file.\n");
416 Debug("Reading %s\n", vmlinuz_file);
417 vmlinuz_buf = ReadFile(vmlinuz_file, &vmlinuz_size);
418 if (!vmlinuz_buf)
419 Fatal("Error reading vmlinuz file.\n");
420 Debug(" vmlinuz file size=0x%" PRIx64 "\n",
421 vmlinuz_size);
422 if (!vmlinuz_size)
423 Fatal("Empty vmlinuz file\n");
Bill Richardson31d95c22014-08-24 22:07:17 -0700424
Bill Richardsonf318ee22014-09-23 14:30:30 -0700425 kblob_data = CreateKernelBlob(
426 vmlinuz_buf, vmlinuz_size,
427 arch, kernel_body_load_address,
428 t_config_data, t_config_size,
429 t_bootloader_data, t_bootloader_size,
430 &kblob_size);
431 if (!kblob_data)
432 Fatal("Unable to create kernel blob\n");
Bill Richardson31d95c22014-08-24 22:07:17 -0700433
Bill Richardsonf318ee22014-09-23 14:30:30 -0700434 Debug("kblob_size = 0x%" PRIx64 "\n", kblob_size);
435
436 vblock_data = SignKernelBlob(kblob_data, kblob_size, opt_pad,
437 version, kernel_body_load_address,
438 t_keyblock, signpriv_key,
439 &vblock_size);
440 if (!vblock_data)
441 Fatal("Unable to sign kernel blob\n");
442
443 Debug("vblock_size = 0x%" PRIx64 "\n", vblock_size);
444
445 if (opt_vblockonly)
446 rv = WriteSomeParts(filename,
447 vblock_data, vblock_size,
448 NULL, 0);
449 else
450 rv = WriteSomeParts(filename,
451 vblock_data, vblock_size,
452 kblob_data, kblob_size);
453 return rv;
Bill Richardson31d95c22014-08-24 22:07:17 -0700454
455 case OPT_MODE_REPACK:
456
457 /* Required */
458
459 if (!signprivkey_file)
460 Fatal("Missing required signprivate file.\n");
461
462 signpriv_key = PrivateKeyRead(signprivkey_file);
463 if (!signpriv_key)
464 Fatal("Error reading signing key.\n");
465
466 if (!oldfile)
467 Fatal("Missing previously packed blob.\n");
468
Bill Richardsonf318ee22014-09-23 14:30:30 -0700469 /* Load the kernel partition */
470 kpart_data = ReadOldKPartFromFileOrDie(oldfile, &kpart_size);
Bill Richardson31d95c22014-08-24 22:07:17 -0700471
Bill Richardson9bfe2c92015-01-27 12:21:04 -0800472 /* Make sure we have a kernel partition */
473 if (FILE_TYPE_KERN_PREAMBLE !=
Bill Richardson25593382015-01-30 12:22:28 -0800474 futil_file_type_buf(kpart_data, kpart_size))
Bill Richardson9bfe2c92015-01-27 12:21:04 -0800475 Fatal("%s is not a kernel blob\n", oldfile);
476
Bill Richardsonf318ee22014-09-23 14:30:30 -0700477 kblob_data = UnpackKPart(kpart_data, kpart_size, opt_pad,
478 &keyblock, &preamble, &kblob_size);
Bill Richardson31d95c22014-08-24 22:07:17 -0700479
Bill Richardsonf318ee22014-09-23 14:30:30 -0700480 if (!kblob_data)
481 Fatal("Unable to unpack kernel partition\n");
Bill Richardson31d95c22014-08-24 22:07:17 -0700482
Bill Richardsonf318ee22014-09-23 14:30:30 -0700483 kernel_body_load_address = preamble->body_load_address;
Bill Richardson31d95c22014-08-24 22:07:17 -0700484
Bill Richardsonf318ee22014-09-23 14:30:30 -0700485 /* Update the config if asked */
Bill Richardson31d95c22014-08-24 22:07:17 -0700486 if (config_file) {
Bill Richardson31d95c22014-08-24 22:07:17 -0700487 Debug("Reading %s\n", config_file);
Bill Richardsonf318ee22014-09-23 14:30:30 -0700488 t_config_data =
489 ReadConfigFile(config_file, &t_config_size);
490 if (!t_config_data)
Bill Richardson31d95c22014-08-24 22:07:17 -0700491 Fatal("Error reading config file.\n");
Bill Richardsonf318ee22014-09-23 14:30:30 -0700492 if (0 != UpdateKernelBlobConfig(
493 kblob_data, kblob_size,
494 t_config_data, t_config_size))
495 Fatal("Unable to update config\n");
Bill Richardson31d95c22014-08-24 22:07:17 -0700496 }
497
Bill Richardsonf318ee22014-09-23 14:30:30 -0700498 if (!version_str)
499 version = preamble->kernel_version;
500
Bill Richardson31d95c22014-08-24 22:07:17 -0700501 if (keyblock_file) {
Bill Richardsonf318ee22014-09-23 14:30:30 -0700502 t_keyblock =
503 (VbKeyBlockHeader *)ReadFile(keyblock_file, 0);
504 if (!t_keyblock)
Bill Richardson31d95c22014-08-24 22:07:17 -0700505 Fatal("Error reading key block.\n");
506 }
507
Bill Richardsonf1dba022014-10-01 14:10:45 -0700508 /* Reuse previous body size */
Bill Richardsonf318ee22014-09-23 14:30:30 -0700509 vblock_data = SignKernelBlob(kblob_data, kblob_size, opt_pad,
510 version, kernel_body_load_address,
511 t_keyblock ? t_keyblock : keyblock,
512 signpriv_key, &vblock_size);
513 if (!vblock_data)
514 Fatal("Unable to sign kernel blob\n");
Bill Richardson31d95c22014-08-24 22:07:17 -0700515
Bill Richardsonf318ee22014-09-23 14:30:30 -0700516 if (opt_vblockonly)
517 rv = WriteSomeParts(filename,
518 vblock_data, vblock_size,
519 NULL, 0);
520 else
521 rv = WriteSomeParts(filename,
522 vblock_data, vblock_size,
523 kblob_data, kblob_size);
524 return rv;
Bill Richardson31d95c22014-08-24 22:07:17 -0700525
526 case OPT_MODE_VERIFY:
527
528 /* Optional */
529
530 if (signpubkey_file) {
531 signpub_key = PublicKeyRead(signpubkey_file);
532 if (!signpub_key)
533 Fatal("Error reading public key.\n");
534 }
535
536 /* Do it */
537
Bill Richardsonf318ee22014-09-23 14:30:30 -0700538 /* Load the kernel partition */
539 kpart_data = ReadOldKPartFromFileOrDie(filename, &kpart_size);
Bill Richardson31d95c22014-08-24 22:07:17 -0700540
Bill Richardsonf318ee22014-09-23 14:30:30 -0700541 kblob_data = UnpackKPart(kpart_data, kpart_size, opt_pad,
542 0, 0, &kblob_size);
543 if (!kblob_data)
544 Fatal("Unable to unpack kernel partition\n");
545
546 rv = VerifyKernelBlob(kblob_data, kblob_size,
547 signpub_key, keyblock_file, min_version);
548
549 return rv;
Shelley Chenf1f53b32015-01-08 09:13:44 -0800550
551 case OPT_MODE_GET_VMLINUZ:
552
553 if (!vmlinuz_out_file) {
554 fprintf(stderr,
555 "USE: vbutil_kernel --get-vmlinuz <file> "
556 "--vmlinuz-out <file>\n");
557 print_help(argv[0]);
558 return 1;
559 }
560
561 kpart_data = ReadOldKPartFromFileOrDie(filename, &kpart_size);
562
563 kblob_data = UnpackKPart(kpart_data, kpart_size, opt_pad,
564 &keyblock, &preamble, &kblob_size);
565
566 if (!kblob_data)
567 Fatal("Unable to unpack kernel partition\n");
568
569 f = fopen(vmlinuz_out_file, "wb");
570 if (!f) {
571 VbExError("Can't open output file %s\n",
572 vmlinuz_out_file);
573 return 1;
574 }
575
576 /* Now stick 16-bit header followed by kernel block into
577 output */
578 if (VbGetKernelVmlinuzHeader(preamble,
579 &vmlinuz_header_address,
580 &vmlinuz_header_size)
581 != VBOOT_SUCCESS) {
582 Fatal("Unable to retrieve Vmlinuz Header!");
583 }
Shelley Chen1bdc6122015-02-02 10:06:10 -0800584
Shelley Chenf1f53b32015-01-08 09:13:44 -0800585 if (vmlinuz_header_size) {
586 // verify that the 16-bit header is included in the
587 // kblob (to make sure that it's included in the
588 // signature)
589 if (VerifyVmlinuzInsideKBlob(preamble->body_load_address,
590 kblob_size,
591 vmlinuz_header_address,
592 vmlinuz_header_size)) {
593 VbExError("Vmlinuz header not signed!\n");
594 fclose(f);
595 unlink(vmlinuz_out_file);
596 return 1;
597 }
Shelley Chen1bdc6122015-02-02 10:06:10 -0800598 // calculate the vmlinuz_header offset from
599 // the beginning of the kpart_data. The kblob doesn't
600 // include the body_load_offset, but does include
601 // the keyblock and preamble sections.
602 vmlinuz_header_offset = vmlinuz_header_address -
603 preamble->body_load_address +
604 keyblock->key_block_size +
605 preamble->preamble_size;
606 errcount |=
607 (1 != fwrite(kpart_data + vmlinuz_header_offset,
608 vmlinuz_header_size,
609 1,
610 f));
611 }
612 errcount |= (1 != fwrite(kblob_data,
613 kblob_size,
Shelley Chenf1f53b32015-01-08 09:13:44 -0800614 1,
615 f));
Shelley Chen1bdc6122015-02-02 10:06:10 -0800616 if (errcount) {
Shelley Chenf1f53b32015-01-08 09:13:44 -0800617 VbExError("Can't write output file %s\n",
618 vmlinuz_out_file);
619 fclose(f);
620 unlink(vmlinuz_out_file);
621 return 1;
622 }
623
624 fclose(f);
Shelley Chen1bdc6122015-02-02 10:06:10 -0800625 return 0;
Bill Richardson31d95c22014-08-24 22:07:17 -0700626 }
627
628 fprintf(stderr,
Shelley Chenf1f53b32015-01-08 09:13:44 -0800629 "You must specify a mode: "
630 "--pack, --repack, --verify, or --get-vmlinuz\n");
Bill Richardson779796f2014-09-23 11:47:40 -0700631 print_help(argv[0]);
632 return 1;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700633}
Bill Richardson6f396152014-07-15 12:52:19 -0700634
Bill Richardson4dad6902014-12-03 16:13:33 -0800635DECLARE_FUTIL_COMMAND(vbutil_kernel, do_vbutil_kernel,
Bill Richardsonf318ee22014-09-23 14:30:30 -0700636 "Creates, signs, and verifies the kernel partition",
Bill Richardson779796f2014-09-23 11:47:40 -0700637 print_help);