blob: 740c3af4f77f0b2d45582ce7e635c343c4de3cf4 [file] [log] [blame]
Bill Richardson6f396152014-07-15 12:52:19 -07001/* Copyright 2012 The Chromium OS Authors. All rights reserved.
Randall Spangler7d6898d2010-06-11 09:22:13 -07002 * Use of this source code is governed by a BSD-style license that can be
3 * found in the LICENSE file.
4 *
5 * Verified boot kernel utility
6 */
7
Bill Richardsona08b5c92010-06-30 21:59:43 -07008#include <errno.h>
Vincent Palatin56c85db2012-09-05 15:35:12 -07009#include <fcntl.h>
Randall Spangler7d6898d2010-06-11 09:22:13 -070010#include <getopt.h>
Bill Richardson31d95c22014-08-24 22:07:17 -070011#include <inttypes.h> /* For PRIu64 */
Vincent Palatin56c85db2012-09-05 15:35:12 -070012#include <sys/ioctl.h>
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 <stddef.h>
16#include <stdio.h>
17#include <stdlib.h>
Bill Richardsona08b5c92010-06-30 21:59:43 -070018#include <string.h>
19#include <sys/stat.h>
20#include <sys/types.h>
Randall Spangler7d6898d2010-06-11 09:22:13 -070021#include <unistd.h>
22
23#include "cryptolib.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 Richardson78299022014-06-20 14:33:00 -070027#include "util_misc.h"
Randall Spangler7d6898d2010-06-11 09:22:13 -070028#include "vboot_common.h"
29
Bill Richardson72e344d2012-03-19 12:47:18 -070030/* Global opts */
Bill Richardson779796f2014-09-23 11:47:40 -070031static int opt_debug;
32static int opt_verbose;
33static int opt_vblockonly;
Bill Richardson72e344d2012-03-19 12:47:18 -070034static uint64_t opt_pad = 65536;
Bill Richardson249677d2010-06-23 11:16:37 -070035
Randall Spangler7d6898d2010-06-11 09:22:13 -070036/* Command line options */
37enum {
Bill Richardson31d95c22014-08-24 22:07:17 -070038 OPT_MODE_PACK = 1000,
39 OPT_MODE_REPACK,
40 OPT_MODE_VERIFY,
41 OPT_ARCH,
42 OPT_OLDBLOB,
43 OPT_KLOADADDR,
44 OPT_KEYBLOCK,
45 OPT_SIGNPUBKEY,
46 OPT_SIGNPRIVATE,
47 OPT_VERSION,
48 OPT_VMLINUZ,
49 OPT_BOOTLOADER,
50 OPT_CONFIG,
51 OPT_VBLOCKONLY,
52 OPT_PAD,
53 OPT_VERBOSE,
54 OPT_MINVERSION,
Randall Spangler7d6898d2010-06-11 09:22:13 -070055};
56
Bill Richardson72e344d2012-03-19 12:47:18 -070057typedef enum {
Bill Richardson31d95c22014-08-24 22:07:17 -070058 ARCH_ARM,
59 ARCH_X86, /* default */
60 ARCH_MIPS
Bill Richardson72e344d2012-03-19 12:47:18 -070061} arch_t;
Che-Liang Chiou03762032011-02-22 11:16:51 +080062
Mike Frysinger7351ed72014-08-18 10:47:42 -040063static const struct option long_opts[] = {
Bill Richardson31d95c22014-08-24 22:07:17 -070064 {"pack", 1, 0, OPT_MODE_PACK},
65 {"repack", 1, 0, OPT_MODE_REPACK},
66 {"verify", 1, 0, OPT_MODE_VERIFY},
67 {"arch", 1, 0, OPT_ARCH},
68 {"oldblob", 1, 0, OPT_OLDBLOB},
69 {"kloadaddr", 1, 0, OPT_KLOADADDR},
70 {"keyblock", 1, 0, OPT_KEYBLOCK},
71 {"signpubkey", 1, 0, OPT_SIGNPUBKEY},
72 {"signprivate", 1, 0, OPT_SIGNPRIVATE},
73 {"version", 1, 0, OPT_VERSION},
74 {"minversion", 1, 0, OPT_MINVERSION},
75 {"vmlinuz", 1, 0, OPT_VMLINUZ},
76 {"bootloader", 1, 0, OPT_BOOTLOADER},
77 {"config", 1, 0, OPT_CONFIG},
78 {"vblockonly", 0, 0, OPT_VBLOCKONLY},
79 {"pad", 1, 0, OPT_PAD},
80 {"verbose", 0, &opt_verbose, 1},
81 {"debug", 0, &opt_debug, 1},
82 {NULL, 0, 0, 0}
Randall Spangler7d6898d2010-06-11 09:22:13 -070083};
84
85
Bill Richardson31d95c22014-08-24 22:07:17 -070086
87static const char usage[] =
Bill Richardson31d95c22014-08-24 22:07:17 -070088 "\n"
Bill Richardson779796f2014-09-23 11:47:40 -070089 "Usage: " MYNAME " %s --pack <file> [PARAMETERS]\n"
Bill Richardson31d95c22014-08-24 22:07:17 -070090 "\n"
91 " Required parameters:\n"
92 " --keyblock <file> Key block in .keyblock format\n"
93 " --signprivate <file> Private key to sign kernel data,\n"
94 " in .vbprivk format\n"
95 " --version <number> Kernel version\n"
96 " --vmlinuz <file> Linux kernel bzImage file\n"
97 " --bootloader <file> Bootloader stub\n"
98 " --config <file> Command line file\n"
99 " --arch <arch> Cpu architecture (default x86)\n"
100 "\n"
101 " Optional:\n"
102 " --kloadaddr <address> Assign kernel body load address\n"
103 " --pad <number> Verification padding size in bytes\n"
104 " --vblockonly Emit just the verification blob\n"
105 "\nOR\n\n"
Bill Richardson779796f2014-09-23 11:47:40 -0700106 "Usage: " MYNAME " %s --repack <file> [PARAMETERS]\n"
Bill Richardson31d95c22014-08-24 22:07:17 -0700107 "\n"
108 " Required parameters:\n"
109 " --signprivate <file> Private key to sign kernel data,\n"
110 " in .vbprivk format\n"
111 " --oldblob <file> Previously packed kernel blob\n"
112 " (including verfication blob)\n"
113 "\n"
114 " Optional:\n"
115 " --keyblock <file> Key block in .keyblock format\n"
116 " --config <file> New command line file\n"
117 " --version <number> Kernel version\n"
118 " --kloadaddr <address> Assign kernel body load address\n"
119 " --pad <number> Verification blob size in bytes\n"
120 " --vblockonly Emit just the verification blob\n"
121 "\nOR\n\n"
Bill Richardson779796f2014-09-23 11:47:40 -0700122 "Usage: " MYNAME " %s --verify <file> [PARAMETERS]\n"
Bill Richardson31d95c22014-08-24 22:07:17 -0700123 "\n"
124 " Optional:\n"
125 " --signpubkey <file>"
126 " Public key to verify kernel keyblock,\n"
127 " in .vbpubk format\n"
128 " --verbose Print a more detailed report\n"
129 " --keyblock <file> Outputs the verified key block,\n"
130 " in .keyblock format\n"
131 " --pad <number> Verification padding size in bytes\n"
132 " --minversion <number> Minimum combined kernel key version\n"
133 " and kernel version\n"
134 "\n";
135
136
Randall Spangler7d6898d2010-06-11 09:22:13 -0700137/* Print help and return error */
Bill Richardson779796f2014-09-23 11:47:40 -0700138static void print_help(const char *progname)
Bill Richardson31d95c22014-08-24 22:07:17 -0700139{
Bill Richardson779796f2014-09-23 11:47:40 -0700140 printf(usage, progname, progname, progname);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700141}
142
Bill Richardson31d95c22014-08-24 22:07:17 -0700143static void Debug(const char *format, ...)
144{
145 if (!opt_debug)
146 return;
Bill Richardson249677d2010-06-23 11:16:37 -0700147
Bill Richardson31d95c22014-08-24 22:07:17 -0700148 va_list ap;
149 va_start(ap, format);
150 fprintf(stderr, "DEBUG: ");
151 vfprintf(stderr, format, ap);
152 va_end(ap);
Bill Richardson249677d2010-06-23 11:16:37 -0700153}
154
Bill Richardson31d95c22014-08-24 22:07:17 -0700155static void Fatal(const char *format, ...)
156{
157 va_list ap;
158 va_start(ap, format);
159 fprintf(stderr, "ERROR: ");
160 vfprintf(stderr, format, ap);
161 va_end(ap);
162 exit(1);
Bill Richardson72e344d2012-03-19 12:47:18 -0700163}
164
Bill Richardson2f6a71f2010-10-14 09:25:39 -0700165/* Return an explanation when fread() fails. */
Bill Richardson779796f2014-09-23 11:47:40 -0700166static const char *error_fread(FILE *fp)
Bill Richardson31d95c22014-08-24 22:07:17 -0700167{
168 const char *retval = "beats me why";
169 if (feof(fp))
170 retval = "EOF";
171 else if (ferror(fp))
172 retval = strerror(errno);
173 clearerr(fp);
174 return retval;
Bill Richardson2f6a71f2010-10-14 09:25:39 -0700175}
Randall Spangler7d6898d2010-06-11 09:22:13 -0700176
177/* Return the smallest integral multiple of [alignment] that is equal
178 * to or greater than [val]. Used to determine the number of
179 * pages/sectors/blocks/whatever needed to contain [val]
180 * items/bytes/etc. */
Bill Richardson31d95c22014-08-24 22:07:17 -0700181static uint64_t roundup(uint64_t val, uint64_t alignment)
182{
183 uint64_t rem = val % alignment;
184 if (rem)
185 return val + (alignment - rem);
186 return val;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700187}
188
Randall Spangler7d6898d2010-06-11 09:22:13 -0700189/* Match regexp /\b--\b/ to delimit the start of the kernel commandline. If we
190 * don't find one, we'll use the whole thing. */
Bill Richardson31d95c22014-08-24 22:07:17 -0700191static unsigned int find_cmdline_start(char *input, unsigned int max_len)
192{
193 int start = 0;
194 int i;
195 for (i = 0; i < max_len - 1 && input[i]; i++) {
196 if ('-' == input[i] && '-' == input[i + 1]) {
197 if ((i == 0 || ' ' == input[i - 1]) &&
198 (i + 2 >= max_len || ' ' == input[i + 2])) {
199 /* found "--" with nothing before or after it */
200 start = i + 2; /* hope for a trailing '\0' */
201 break;
202 }
203 }
204 }
205 while (' ' == input[start]) /* skip leading spaces */
206 start++;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700207
Bill Richardson31d95c22014-08-24 22:07:17 -0700208 return start;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700209}
210
Bill Richardson72e344d2012-03-19 12:47:18 -0700211/****************************************************************************/
212/* Here are globals containing all the bits & pieces I'm working on. */
213
214/* The individual parts that go into the kernel blob */
Bill Richardson6f396152014-07-15 12:52:19 -0700215static uint8_t *g_kernel_data;
216static uint64_t g_kernel_size;
217static uint8_t *g_param_data;
218static uint64_t g_param_size;
219static uint8_t *g_config_data;
220static uint64_t g_config_size;
221static uint8_t *g_bootloader_data;
222static uint64_t g_bootloader_size;
223static uint64_t g_bootloader_address;
Bill Richardsonc8b9ca62012-03-14 10:54:05 -0700224
Bill Richardson72e344d2012-03-19 12:47:18 -0700225/* The individual parts of the verification blob (including the data that
226 * immediately follows the headers) */
Bill Richardson31d95c22014-08-24 22:07:17 -0700227static VbKeyBlockHeader *g_keyblock;
228static VbKernelPreambleHeader *g_preamble;
vbendebb2b0fcc2010-07-15 15:09:47 -0700229
Bill Richardson72e344d2012-03-19 12:47:18 -0700230/****************************************************************************/
Bill Richardsona08b5c92010-06-30 21:59:43 -0700231
vbendebb2b0fcc2010-07-15 15:09:47 -0700232/*
233 * Read the kernel command line from a file. Get rid of \n characters along
234 * the way and verify that the line fits into a 4K buffer.
235 *
236 * Return the buffer contaning the line on success (and set the line length
237 * using the passed in parameter), or NULL in case something goes wrong.
238 */
Bill Richardson779796f2014-09-23 11:47:40 -0700239static uint8_t *sReadConfigFile(const char *config_file, uint64_t *config_size)
vbendebb2b0fcc2010-07-15 15:09:47 -0700240{
Bill Richardson31d95c22014-08-24 22:07:17 -0700241 uint8_t *config_buf;
242 int ii;
vbendebb2b0fcc2010-07-15 15:09:47 -0700243
Bill Richardson31d95c22014-08-24 22:07:17 -0700244 config_buf = ReadFile(config_file, config_size);
245 Debug(" config file size=0x%" PRIx64 "\n", *config_size);
246 if (CROS_CONFIG_SIZE <= *config_size) { /* room for trailing '\0' */
247 VbExError("Config file %s is too large (>= %d bytes)\n",
248 config_file, CROS_CONFIG_SIZE);
249 return NULL;
250 }
vbendebb2b0fcc2010-07-15 15:09:47 -0700251
Bill Richardson31d95c22014-08-24 22:07:17 -0700252 /* Replace newlines with spaces */
Bill Richardson779796f2014-09-23 11:47:40 -0700253 for (ii = 0; ii < *config_size; ii++)
254 if ('\n' == config_buf[ii])
Bill Richardson31d95c22014-08-24 22:07:17 -0700255 config_buf[ii] = ' ';
Bill Richardson779796f2014-09-23 11:47:40 -0700256
Bill Richardson31d95c22014-08-24 22:07:17 -0700257 return config_buf;
vbendebb2b0fcc2010-07-15 15:09:47 -0700258}
259
Bill Richardson72e344d2012-03-19 12:47:18 -0700260/* Offset of kernel command line string from start of packed kernel blob */
Bill Richardson779796f2014-09-23 11:47:40 -0700261static uint64_t CmdLineOffset(VbKernelPreambleHeader *preamble)
Bill Richardson31d95c22014-08-24 22:07:17 -0700262{
263 return preamble->bootloader_address - preamble->body_load_address -
264 CROS_CONFIG_SIZE - CROS_PARAMS_SIZE;
Bill Richardson72e344d2012-03-19 12:47:18 -0700265}
266
267/* This initializes g_vmlinuz and g_param from a standard vmlinuz file.
268 * It returns 0 on error. */
269static int ImportVmlinuzFile(const char *vmlinuz_file, arch_t arch,
Bill Richardson31d95c22014-08-24 22:07:17 -0700270 uint64_t kernel_body_load_address)
271{
272 uint8_t *kernel_buf;
273 uint64_t kernel_size;
274 uint64_t kernel32_start = 0;
275 uint64_t kernel32_size = 0;
276 struct linux_kernel_params *params = NULL, *lh = NULL;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700277
Bill Richardson31d95c22014-08-24 22:07:17 -0700278 /* Read the kernel */
279 Debug("Reading %s\n", vmlinuz_file);
280 kernel_buf = ReadFile(vmlinuz_file, &kernel_size);
281 if (!kernel_buf)
282 return 0;
283 Debug(" kernel file size=0x%" PRIx64 "\n", kernel_size);
284 if (!kernel_size)
285 Fatal("Empty kernel file\n");
Bill Richardson72e344d2012-03-19 12:47:18 -0700286
Bill Richardson31d95c22014-08-24 22:07:17 -0700287 /* Go ahead and allocate the param region anyway. I don't think we need
288 * it for non-x86, but let's keep it for now. */
289 g_param_size = CROS_PARAMS_SIZE;
290 g_param_data = VbExMalloc(g_param_size);
291 Memset(g_param_data, 0, g_param_size);
Bill Richardson72e344d2012-03-19 12:47:18 -0700292
Bill Richardson31d95c22014-08-24 22:07:17 -0700293 /* Unless we're handling x86, the kernel is the kernel; we're done. */
294 if (arch != ARCH_X86) {
295 g_kernel_data = kernel_buf;
296 g_kernel_size = kernel_size;
297 return 1;
298 }
Randall Spangler7d6898d2010-06-11 09:22:13 -0700299
Bill Richardson31d95c22014-08-24 22:07:17 -0700300 /* The first part of the x86 vmlinuz is a header, followed by a
301 * real-mode boot stub. We only want the 32-bit part. */
302 lh = (struct linux_kernel_params *)kernel_buf;
303 kernel32_start = (lh->setup_sects + 1) << 9;
304 if (kernel32_start >= kernel_size)
305 Fatal("Malformed kernel\n");
306 kernel32_size = kernel_size - kernel32_start;
Bill Richardson72e344d2012-03-19 12:47:18 -0700307
Bill Richardson31d95c22014-08-24 22:07:17 -0700308 Debug(" kernel32_start=0x%" PRIx64 "\n", kernel32_start);
309 Debug(" kernel32_size=0x%" PRIx64 "\n", kernel32_size);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700310
Bill Richardson31d95c22014-08-24 22:07:17 -0700311 /* Keep just the 32-bit kernel. */
312 if (kernel32_size) {
313 g_kernel_size = kernel32_size;
314 g_kernel_data = VbExMalloc(g_kernel_size);
315 Memcpy(g_kernel_data, kernel_buf + kernel32_start,
316 kernel32_size);
317 }
Randall Spangler7d6898d2010-06-11 09:22:13 -0700318
Bill Richardson31d95c22014-08-24 22:07:17 -0700319 /* Copy the original zeropage data from kernel_buf into g_param_data,
320 * then tweak a few fields for our purposes */
321 params = (struct linux_kernel_params *)(g_param_data);
322 Memcpy(&(params->setup_sects), &(lh->setup_sects),
323 offsetof(struct linux_kernel_params, e820_entries)
324 - offsetof(struct linux_kernel_params, setup_sects));
325 params->boot_flag = 0;
326 params->ramdisk_image = 0; /* we don't support initrd */
327 params->ramdisk_size = 0;
328 params->type_of_loader = 0xff;
329 /* We need to point to the kernel commandline arg. On disk, it will come
330 * right after the 32-bit part of the kernel. */
331 params->cmd_line_ptr = kernel_body_load_address +
332 roundup(kernel32_size, CROS_ALIGN) +
333 find_cmdline_start((char *)g_config_data, g_config_size);
334 Debug(" cmdline_addr=0x%x\n", params->cmd_line_ptr);
335 Debug(" version=0x%x\n", params->version);
336 Debug(" kernel_alignment=0x%x\n", params->kernel_alignment);
337 Debug(" relocatable_kernel=0x%x\n", params->relocatable_kernel);
338 /* A fake e820 memory map with 2 entries */
339 params->n_e820_entry = 2;
340 params->e820_entries[0].start_addr = 0x00000000;
341 params->e820_entries[0].segment_size = 0x00001000;
342 params->e820_entries[0].segment_type = E820_TYPE_RAM;
343 params->e820_entries[1].start_addr = 0xfffff000;
344 params->e820_entries[1].segment_size = 0x00001000;
345 params->e820_entries[1].segment_type = E820_TYPE_RESERVED;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700346
Bill Richardson31d95c22014-08-24 22:07:17 -0700347 /* done */
348 free(kernel_buf);
349 return 1;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700350}
351
Bill Richardson72e344d2012-03-19 12:47:18 -0700352/* This returns just the kernel blob, with the verification blob separated
353 * and copied to new memory in g_keyblock and g_preamble. */
Bill Richardson31d95c22014-08-24 22:07:17 -0700354static uint8_t *ReadOldBlobFromFileOrDie(const char *filename,
Bill Richardson779796f2014-09-23 11:47:40 -0700355 uint64_t *size_ptr)
Bill Richardson31d95c22014-08-24 22:07:17 -0700356{
357 FILE *fp = NULL;
358 struct stat statbuf;
359 VbKeyBlockHeader *key_block;
360 VbKernelPreambleHeader *preamble;
361 uint64_t now = 0;
362 uint8_t *buf;
363 uint8_t *kernel_blob_data;
364 uint64_t kernel_blob_size;
365 uint64_t file_size = 0;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700366
Bill Richardson31d95c22014-08-24 22:07:17 -0700367 if (0 != stat(filename, &statbuf))
368 Fatal("Unable to stat %s: %s\n", filename, strerror(errno));
Bill Richardsona08b5c92010-06-30 21:59:43 -0700369
Bill Richardson31d95c22014-08-24 22:07:17 -0700370 if (S_ISBLK(statbuf.st_mode)) {
Bill Richardson779796f2014-09-23 11:47:40 -0700371 int fd = open(filename, O_RDONLY);
372 if (fd >= 0) {
Bill Richardson31d95c22014-08-24 22:07:17 -0700373 ioctl(fd, BLKGETSIZE64, &file_size);
374 close(fd);
375 }
376 } else {
377 file_size = statbuf.st_size;
378 }
379 Debug("%s size is 0x%" PRIx64 "\n", filename, file_size);
380 if (file_size < opt_pad)
381 Fatal("%s is too small to be a valid kernel blob\n");
Bill Richardsona08b5c92010-06-30 21:59:43 -0700382
Bill Richardson31d95c22014-08-24 22:07:17 -0700383 Debug("Reading %s\n", filename);
384 fp = fopen(filename, "rb");
385 if (!fp)
386 Fatal("Unable to open file %s: %s\n", filename,
387 strerror(errno));
Bill Richardsona08b5c92010-06-30 21:59:43 -0700388
Bill Richardson31d95c22014-08-24 22:07:17 -0700389 buf = VbExMalloc(opt_pad);
390 if (1 != fread(buf, opt_pad, 1, fp))
391 Fatal("Unable to read header from %s: %s\n", filename,
392 error_fread(fp));
vbendebb2b0fcc2010-07-15 15:09:47 -0700393
Bill Richardson31d95c22014-08-24 22:07:17 -0700394 /* Sanity-check the key_block */
395 key_block = (VbKeyBlockHeader *) buf;
396 Debug("Keyblock is 0x%" PRIx64 " bytes\n", key_block->key_block_size);
397 now += key_block->key_block_size;
398 if (now > file_size)
399 Fatal("key_block_size advances past the end of the blob\n");
400 if (now > opt_pad)
401 Fatal("key_block_size advances past %" PRIu64 " byte padding\n",
402 opt_pad);
403 /* LGTM */
404 g_keyblock = (VbKeyBlockHeader *) VbExMalloc(key_block->key_block_size);
405 Memcpy(g_keyblock, key_block, key_block->key_block_size);
Bill Richardsona08b5c92010-06-30 21:59:43 -0700406
Bill Richardson31d95c22014-08-24 22:07:17 -0700407 /* And the preamble */
408 preamble = (VbKernelPreambleHeader *) (buf + now);
409 Debug("Preamble is 0x%" PRIx64 " bytes\n", preamble->preamble_size);
410 now += preamble->preamble_size;
411 if (now > file_size)
412 Fatal("preamble_size advances past the end of the blob\n");
413 if (now > opt_pad)
414 Fatal("preamble_size advances past %" PRIu64 " byte padding\n",
415 opt_pad);
416 /* LGTM */
417 Debug(" kernel_version = %d\n", preamble->kernel_version);
418 Debug(" bootloader_address = 0x%" PRIx64 "\n",
419 preamble->bootloader_address);
420 Debug(" bootloader_size = 0x%" PRIx64 "\n", preamble->bootloader_size);
421 Debug(" kern_blob_size = 0x%" PRIx64 "\n",
422 preamble->body_signature.data_size);
423 g_preamble =
424 (VbKernelPreambleHeader *) VbExMalloc(preamble->preamble_size);
425 Memcpy(g_preamble, preamble, preamble->preamble_size);
Bill Richardsona08b5c92010-06-30 21:59:43 -0700426
Bill Richardson31d95c22014-08-24 22:07:17 -0700427 /* Now for the kernel blob */
428 Debug("kernel blob is at offset 0x%" PRIx64 "\n", now);
429 if (0 != fseek(fp, now, SEEK_SET))
430 Fatal("Unable to seek to 0x%" PRIx64 " in %s: %s\n", now,
431 filename, strerror(errno));
Bill Richardsona08b5c92010-06-30 21:59:43 -0700432
Bill Richardson31d95c22014-08-24 22:07:17 -0700433 /* Sanity check */
434 kernel_blob_size = file_size - now;
435 if (!kernel_blob_size)
436 Fatal("No kernel blob found\n");
437 if (kernel_blob_size < preamble->body_signature.data_size)
438 fprintf(stderr,
439 "Warning: kernel file only has 0x%" PRIx64 " bytes\n",
440 kernel_blob_size);
441 kernel_blob_data = VbExMalloc(kernel_blob_size);
Bill Richardsona08b5c92010-06-30 21:59:43 -0700442
Bill Richardson31d95c22014-08-24 22:07:17 -0700443 /* Read it in */
444 if (1 != fread(kernel_blob_data, kernel_blob_size, 1, fp))
445 Fatal("Unable to read kernel blob from %s: %s\n", filename,
446 error_fread(fp));
Bill Richardsona08b5c92010-06-30 21:59:43 -0700447
Bill Richardson31d95c22014-08-24 22:07:17 -0700448 /* Done */
449 VbExFree(buf);
Bill Richardsona08b5c92010-06-30 21:59:43 -0700450
Bill Richardson31d95c22014-08-24 22:07:17 -0700451 if (size_ptr)
452 *size_ptr = kernel_blob_size;
Bill Richardson72e344d2012-03-19 12:47:18 -0700453
Bill Richardson31d95c22014-08-24 22:07:17 -0700454 return kernel_blob_data;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700455}
456
Bill Richardson72e344d2012-03-19 12:47:18 -0700457/* Split a kernel blob into separate g_kernel, g_param, g_config, and
458 * g_bootloader parts. */
Bill Richardson779796f2014-09-23 11:47:40 -0700459static void UnpackKernelBlob(uint8_t *kernel_blob_data,
Bill Richardson31d95c22014-08-24 22:07:17 -0700460 uint64_t kernel_blob_size)
461{
Bill Richardson72e344d2012-03-19 12:47:18 -0700462
Bill Richardson31d95c22014-08-24 22:07:17 -0700463 uint64_t k_blob_size = g_preamble->body_signature.data_size;
464 uint64_t k_blob_ofs = 0;
465 uint64_t b_size = g_preamble->bootloader_size;
466 uint64_t b_ofs = k_blob_ofs + g_preamble->bootloader_address -
467 g_preamble->body_load_address;
468 uint64_t p_ofs = b_ofs - CROS_CONFIG_SIZE;
469 uint64_t c_ofs = p_ofs - CROS_PARAMS_SIZE;
Bill Richardson72e344d2012-03-19 12:47:18 -0700470
Bill Richardson31d95c22014-08-24 22:07:17 -0700471 Debug("k_blob_size = 0x%" PRIx64 "\n", k_blob_size);
472 Debug("k_blob_ofs = 0x%" PRIx64 "\n", k_blob_ofs);
473 Debug("b_size = 0x%" PRIx64 "\n", b_size);
474 Debug("b_ofs = 0x%" PRIx64 "\n", b_ofs);
475 Debug("p_ofs = 0x%" PRIx64 "\n", p_ofs);
476 Debug("c_ofs = 0x%" PRIx64 "\n", c_ofs);
Bill Richardson72e344d2012-03-19 12:47:18 -0700477
Bill Richardson31d95c22014-08-24 22:07:17 -0700478 g_kernel_size = c_ofs;
479 g_kernel_data = VbExMalloc(g_kernel_size);
480 Memcpy(g_kernel_data, kernel_blob_data, g_kernel_size);
Bill Richardson72e344d2012-03-19 12:47:18 -0700481
Bill Richardson31d95c22014-08-24 22:07:17 -0700482 g_param_size = CROS_PARAMS_SIZE;
483 g_param_data = VbExMalloc(g_param_size);
484 Memcpy(g_param_data, kernel_blob_data + p_ofs, g_param_size);
Bill Richardson72e344d2012-03-19 12:47:18 -0700485
Bill Richardson31d95c22014-08-24 22:07:17 -0700486 g_config_size = CROS_CONFIG_SIZE;
487 g_config_data = VbExMalloc(g_config_size);
488 Memcpy(g_config_data, kernel_blob_data + c_ofs, g_config_size);
Bill Richardson72e344d2012-03-19 12:47:18 -0700489
Bill Richardson31d95c22014-08-24 22:07:17 -0700490 g_bootloader_size = b_size;
491 g_bootloader_data = VbExMalloc(g_bootloader_size);
492 Memcpy(g_bootloader_data, kernel_blob_data + b_ofs, g_bootloader_size);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700493}
494
Bill Richardson72e344d2012-03-19 12:47:18 -0700495/****************************************************************************/
Randall Spangler7d6898d2010-06-11 09:22:13 -0700496
Bill Richardson779796f2014-09-23 11:47:40 -0700497static uint8_t *CreateKernBlob(uint64_t kernel_body_load_address,
498 arch_t arch, uint64_t *size_ptr)
Bill Richardson31d95c22014-08-24 22:07:17 -0700499{
500 uint8_t *kern_blob;
501 uint64_t kern_blob_size;
502 uint64_t now;
503 uint64_t bootloader_size = roundup(g_bootloader_size, CROS_ALIGN);
Bill Richardsona08b5c92010-06-30 21:59:43 -0700504
Bill Richardson31d95c22014-08-24 22:07:17 -0700505 /* Put the kernel blob together */
506 kern_blob_size = roundup(g_kernel_size, CROS_ALIGN) +
507 CROS_CONFIG_SIZE + CROS_PARAMS_SIZE + bootloader_size;
508 Debug("kern_blob_size=0x%" PRIx64 "\n", kern_blob_size);
509 kern_blob = VbExMalloc(kern_blob_size);
510 Memset(kern_blob, 0, kern_blob_size);
511 now = 0;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700512
Bill Richardson31d95c22014-08-24 22:07:17 -0700513 Debug("kernel goes at kern_blob+0x%" PRIx64 "\n", now);
Bill Richardson72e344d2012-03-19 12:47:18 -0700514
Bill Richardson31d95c22014-08-24 22:07:17 -0700515 Memcpy(kern_blob + now, g_kernel_data, g_kernel_size);
516 now += roundup(g_kernel_size, CROS_ALIGN);
Bill Richardson72e344d2012-03-19 12:47:18 -0700517
Bill Richardson31d95c22014-08-24 22:07:17 -0700518 Debug("config goes at kern_blob+0x%" PRIx64 "\n", now);
519 if (g_config_size)
520 Memcpy(kern_blob + now, g_config_data, g_config_size);
521 now += CROS_CONFIG_SIZE;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700522
Bill Richardson31d95c22014-08-24 22:07:17 -0700523 Debug("params goes at kern_blob+0x%" PRIx64 "\n", now);
Bill Richardson779796f2014-09-23 11:47:40 -0700524 if (g_param_size)
Bill Richardson31d95c22014-08-24 22:07:17 -0700525 Memcpy(kern_blob + now, g_param_data, g_param_size);
Bill Richardson31d95c22014-08-24 22:07:17 -0700526 now += CROS_PARAMS_SIZE;
Bill Richardson4f36ef32010-08-09 17:50:14 -0700527
Bill Richardson31d95c22014-08-24 22:07:17 -0700528 Debug("bootloader goes at kern_blob+0x%" PRIx64 "\n", now);
529 g_bootloader_address = kernel_body_load_address + now;
530 Debug(" bootloader_address=0x%" PRIx64 "\n", g_bootloader_address);
531 Debug(" bootloader_size=0x%" PRIx64 "\n", bootloader_size);
532 if (bootloader_size)
533 Memcpy(kern_blob + now, g_bootloader_data, g_bootloader_size);
534 now += bootloader_size;
535 Debug("end of kern_blob at kern_blob+0x%" PRIx64 "\n", now);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700536
Bill Richardson31d95c22014-08-24 22:07:17 -0700537 /* Done */
538 if (size_ptr)
539 *size_ptr = kern_blob_size;
Che-Liang Chiou03762032011-02-22 11:16:51 +0800540
Bill Richardson31d95c22014-08-24 22:07:17 -0700541 return kern_blob;
542}
Bill Richardsona08b5c92010-06-30 21:59:43 -0700543
Bill Richardson31d95c22014-08-24 22:07:17 -0700544static int Pack(const char *outfile,
Bill Richardson779796f2014-09-23 11:47:40 -0700545 uint8_t *kernel_blob,
Bill Richardson31d95c22014-08-24 22:07:17 -0700546 uint64_t kernel_size,
547 int version,
Bill Richardson779796f2014-09-23 11:47:40 -0700548 uint64_t kernel_body_load_address,
549 VbPrivateKey *signpriv_key)
Bill Richardson31d95c22014-08-24 22:07:17 -0700550{
551 VbSignature *body_sig;
552 FILE *f;
553 uint64_t i;
554 uint64_t written = 0;
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +0800555
Bill Richardson31d95c22014-08-24 22:07:17 -0700556 /* Sign the kernel data */
557 body_sig = CalculateSignature(kernel_blob, kernel_size, signpriv_key);
558 if (!body_sig)
559 Fatal("Error calculating body signature\n");
Randall Spangler7d6898d2010-06-11 09:22:13 -0700560
Bill Richardson31d95c22014-08-24 22:07:17 -0700561 /* Create preamble */
562 g_preamble = CreateKernelPreamble(version,
563 kernel_body_load_address,
564 g_bootloader_address,
565 roundup(g_bootloader_size,
566 CROS_ALIGN), body_sig,
567 opt_pad - g_keyblock->key_block_size,
568 signpriv_key);
569 if (!g_preamble) {
570 VbExError("Error creating preamble.\n");
571 return 1;
572 }
573 /* Write the output file */
574 Debug("writing %s...\n", outfile);
575 f = fopen(outfile, "wb");
576 if (!f) {
577 VbExError("Can't open output file %s\n", outfile);
578 return 1;
579 }
580 Debug("0x%" PRIx64 " bytes of key_block\n", g_keyblock->key_block_size);
581 Debug("0x%" PRIx64 " bytes of preamble\n", g_preamble->preamble_size);
582 i = ((1 != fwrite(g_keyblock, g_keyblock->key_block_size, 1, f)) ||
583 (1 != fwrite(g_preamble, g_preamble->preamble_size, 1, f)));
584 if (i) {
585 VbExError("Can't write output file %s\n", outfile);
586 fclose(f);
587 unlink(outfile);
588 return 1;
589 }
590 written += g_keyblock->key_block_size;
591 written += g_preamble->preamble_size;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700592
Bill Richardson31d95c22014-08-24 22:07:17 -0700593 if (!opt_vblockonly) {
594 Debug("0x%" PRIx64 " bytes of kern_blob\n", kernel_size);
595 i = (1 != fwrite(kernel_blob, kernel_size, 1, f));
596 if (i) {
597 fclose(f);
598 unlink(outfile);
599 Fatal("Can't write output file %s\n", outfile);
600 }
601 written += kernel_size;
602 }
603 Debug("0x%" PRIx64 " bytes total\n", written);
604 fclose(f);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700605
Bill Richardson31d95c22014-08-24 22:07:17 -0700606 /* Success */
607 return 0;
608}
Randall Spangler7d6898d2010-06-11 09:22:13 -0700609
Bill Richardson779796f2014-09-23 11:47:40 -0700610static int Verify(uint8_t *kernel_blob,
Bill Richardson31d95c22014-08-24 22:07:17 -0700611 uint64_t kernel_size,
Bill Richardson779796f2014-09-23 11:47:40 -0700612 VbPublicKey *signpub_key,
613 const char *keyblock_outfile,
614 uint64_t min_version)
Bill Richardson31d95c22014-08-24 22:07:17 -0700615{
616 VbPublicKey *data_key;
617 RSAPublicKey *rsa;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700618
Bill Richardson31d95c22014-08-24 22:07:17 -0700619 if (0 != KeyBlockVerify(g_keyblock, g_keyblock->key_block_size,
620 signpub_key, (0 == signpub_key)))
621 Fatal("Error verifying key block.\n");
Randall Spangler7d6898d2010-06-11 09:22:13 -0700622
Bill Richardson31d95c22014-08-24 22:07:17 -0700623 printf("Key block:\n");
624 data_key = &g_keyblock->data_key;
625 if (opt_verbose)
626 printf(" Signature: %s\n",
627 signpub_key ? "valid" : "ignored");
628 printf(" Size: 0x%" PRIx64 "\n",
629 g_keyblock->key_block_size);
630 printf(" Flags: %" PRIu64 " ",
631 g_keyblock->key_block_flags);
632 if (g_keyblock->key_block_flags & KEY_BLOCK_FLAG_DEVELOPER_0)
633 printf(" !DEV");
634 if (g_keyblock->key_block_flags & KEY_BLOCK_FLAG_DEVELOPER_1)
635 printf(" DEV");
636 if (g_keyblock->key_block_flags & KEY_BLOCK_FLAG_RECOVERY_0)
637 printf(" !REC");
638 if (g_keyblock->key_block_flags & KEY_BLOCK_FLAG_RECOVERY_1)
639 printf(" REC");
640 printf("\n");
641 printf(" Data key algorithm: %" PRIu64 " %s\n", data_key->algorithm,
642 (data_key->algorithm < kNumAlgorithms ?
643 algo_strings[data_key->algorithm] : "(invalid)"));
644 printf(" Data key version: %" PRIu64 "\n", data_key->key_version);
645 printf(" Data key sha1sum: ");
646 PrintPubKeySha1Sum(data_key);
647 printf("\n");
Bill Richardsona08b5c92010-06-30 21:59:43 -0700648
Bill Richardson31d95c22014-08-24 22:07:17 -0700649 if (keyblock_outfile) {
650 FILE *f = NULL;
651 f = fopen(keyblock_outfile, "wb");
652 if (!f)
653 Fatal("Can't open key block file %s\n",
654 keyblock_outfile);
655 if (1 != fwrite(g_keyblock, g_keyblock->key_block_size, 1, f))
656 Fatal("Can't write key block file %s\n",
657 keyblock_outfile);
658 fclose(f);
659 }
Randall Spangler7d6898d2010-06-11 09:22:13 -0700660
Bill Richardson31d95c22014-08-24 22:07:17 -0700661 if (data_key->key_version < (min_version >> 16))
662 Fatal("Data key version %" PRIu64
663 " is lower than minimum %" PRIu64 ".\n",
664 data_key->key_version, (min_version >> 16));
Randall Spangler7d6898d2010-06-11 09:22:13 -0700665
Bill Richardson31d95c22014-08-24 22:07:17 -0700666 rsa = PublicKeyToRSA(data_key);
667 if (!rsa)
668 Fatal("Error parsing data key.\n");
Bill Richardsona08b5c92010-06-30 21:59:43 -0700669
Bill Richardson31d95c22014-08-24 22:07:17 -0700670 /* Verify preamble */
671 if (0 !=
672 VerifyKernelPreamble(g_preamble, g_preamble->preamble_size, rsa))
673 Fatal("Error verifying preamble.\n");
vbendebb2b0fcc2010-07-15 15:09:47 -0700674
Bill Richardson31d95c22014-08-24 22:07:17 -0700675 printf("Preamble:\n");
676 printf(" Size: 0x%" PRIx64 "\n",
677 g_preamble->preamble_size);
678 printf(" Header version: %" PRIu32 ".%" PRIu32 "\n",
679 g_preamble->header_version_major,
680 g_preamble->header_version_minor);
681 printf(" Kernel version: %" PRIu64 "\n",
682 g_preamble->kernel_version);
683 printf(" Body load address: 0x%" PRIx64 "\n",
684 g_preamble->body_load_address);
685 printf(" Body size: 0x%" PRIx64 "\n",
686 g_preamble->body_signature.data_size);
687 printf(" Bootloader address: 0x%" PRIx64 "\n",
688 g_preamble->bootloader_address);
689 printf(" Bootloader size: 0x%" PRIx64 "\n",
690 g_preamble->bootloader_size);
Bill Richardsona08b5c92010-06-30 21:59:43 -0700691
Bill Richardson31d95c22014-08-24 22:07:17 -0700692 if (g_preamble->kernel_version < (min_version & 0xFFFF))
693 Fatal("Kernel version %" PRIu64 " is lower than minimum %"
694 PRIu64 ".\n", g_preamble->kernel_version,
695 (min_version & 0xFFFF));
Bill Richardsona08b5c92010-06-30 21:59:43 -0700696
Bill Richardson31d95c22014-08-24 22:07:17 -0700697 /* Verify body */
698 if (0 != VerifyData(kernel_blob, kernel_size,
699 &g_preamble->body_signature, rsa))
700 Fatal("Error verifying kernel body.\n");
701 printf("Body verification succeeded.\n");
Bill Richardson72e344d2012-03-19 12:47:18 -0700702
Bill Richardson31d95c22014-08-24 22:07:17 -0700703 if (opt_verbose)
704 printf("Config:\n%s\n",
705 kernel_blob + CmdLineOffset(g_preamble));
Bill Richardson72e344d2012-03-19 12:47:18 -0700706
Bill Richardson31d95c22014-08-24 22:07:17 -0700707 return 0;
708}
Bill Richardson72e344d2012-03-19 12:47:18 -0700709
Bill Richardson31d95c22014-08-24 22:07:17 -0700710/****************************************************************************/
Bill Richardson72e344d2012-03-19 12:47:18 -0700711
Bill Richardson31d95c22014-08-24 22:07:17 -0700712static int do_vbutil_kernel(int argc, char *argv[])
713{
714 char *filename = NULL;
715 char *oldfile = NULL;
716 char *keyblock_file = NULL;
717 char *signpubkey_file = NULL;
718 char *signprivkey_file = NULL;
719 char *version_str = NULL;
720 int version = -1;
721 char *vmlinuz_file = NULL;
722 char *bootloader_file = NULL;
723 char *config_file = NULL;
724 arch_t arch = ARCH_X86;
725 char *address_str = NULL;
726 uint64_t kernel_body_load_address = CROS_32BIT_ENTRY_ADDR;
727 int mode = 0;
728 int parse_error = 0;
729 uint64_t min_version = 0;
730 char *e;
731 int i;
732 VbPrivateKey *signpriv_key = NULL;
733 VbPublicKey *signpub_key = NULL;
734 uint8_t *kernel_blob = NULL;
735 uint64_t kernel_size = 0;
Bill Richardson72e344d2012-03-19 12:47:18 -0700736
Bill Richardson31d95c22014-08-24 22:07:17 -0700737 while (((i = getopt_long(argc, argv, ":", long_opts, NULL)) != -1) &&
738 !parse_error) {
739 switch (i) {
740 default:
741 case '?':
742 /* Unhandled option */
743 parse_error = 1;
744 break;
Bill Richardson72e344d2012-03-19 12:47:18 -0700745
Bill Richardson31d95c22014-08-24 22:07:17 -0700746 case 0:
747 /* silently handled option */
748 break;
Bill Richardson72e344d2012-03-19 12:47:18 -0700749
Bill Richardson31d95c22014-08-24 22:07:17 -0700750 case OPT_MODE_PACK:
751 case OPT_MODE_REPACK:
752 case OPT_MODE_VERIFY:
753 if (mode && (mode != i)) {
754 fprintf(stderr,
755 "Only one mode can be specified\n");
756 parse_error = 1;
757 break;
758 }
759 mode = i;
760 filename = optarg;
761 break;
Bill Richardson72e344d2012-03-19 12:47:18 -0700762
Bill Richardson31d95c22014-08-24 22:07:17 -0700763 case OPT_ARCH:
764 /* check the first 3 characters to also detect x86_64 */
765 if ((!strncasecmp(optarg, "x86", 3)) ||
766 (!strcasecmp(optarg, "amd64")))
767 arch = ARCH_X86;
768 else if ((!strcasecmp(optarg, "arm")) ||
769 (!strcasecmp(optarg, "aarch64")))
770 arch = ARCH_ARM;
771 else if (!strcasecmp(optarg, "mips"))
772 arch = ARCH_MIPS;
773 else {
774 fprintf(stderr,
775 "Unknown architecture string: %s\n",
776 optarg);
777 parse_error = 1;
778 }
779 break;
Bill Richardson72e344d2012-03-19 12:47:18 -0700780
Bill Richardson31d95c22014-08-24 22:07:17 -0700781 case OPT_OLDBLOB:
782 oldfile = optarg;
783 break;
Bill Richardson72e344d2012-03-19 12:47:18 -0700784
Bill Richardson31d95c22014-08-24 22:07:17 -0700785 case OPT_KLOADADDR:
786 address_str = optarg;
787 kernel_body_load_address = strtoul(optarg, &e, 0);
788 if (!*optarg || (e && *e)) {
789 fprintf(stderr, "Invalid --kloadaddr\n");
790 parse_error = 1;
791 }
792 break;
Bill Richardson72e344d2012-03-19 12:47:18 -0700793
Bill Richardson31d95c22014-08-24 22:07:17 -0700794 case OPT_KEYBLOCK:
795 keyblock_file = optarg;
796 break;
Bill Richardson72e344d2012-03-19 12:47:18 -0700797
Bill Richardson31d95c22014-08-24 22:07:17 -0700798 case OPT_SIGNPUBKEY:
799 signpubkey_file = optarg;
800 break;
Bill Richardson72e344d2012-03-19 12:47:18 -0700801
Bill Richardson31d95c22014-08-24 22:07:17 -0700802 case OPT_SIGNPRIVATE:
803 signprivkey_file = optarg;
804 break;
Bill Richardson72e344d2012-03-19 12:47:18 -0700805
Bill Richardson31d95c22014-08-24 22:07:17 -0700806 case OPT_VMLINUZ:
807 vmlinuz_file = optarg;
808 break;
Bill Richardson72e344d2012-03-19 12:47:18 -0700809
Bill Richardson31d95c22014-08-24 22:07:17 -0700810 case OPT_BOOTLOADER:
811 bootloader_file = optarg;
812 break;
Bill Richardson72e344d2012-03-19 12:47:18 -0700813
Bill Richardson31d95c22014-08-24 22:07:17 -0700814 case OPT_CONFIG:
815 config_file = optarg;
816 break;
Bill Richardson72e344d2012-03-19 12:47:18 -0700817
Bill Richardson31d95c22014-08-24 22:07:17 -0700818 case OPT_VBLOCKONLY:
819 opt_vblockonly = 1;
820 break;
Bill Richardson72e344d2012-03-19 12:47:18 -0700821
Bill Richardson31d95c22014-08-24 22:07:17 -0700822 case OPT_VERSION:
823 version_str = optarg;
824 version = strtoul(optarg, &e, 0);
825 if (!*optarg || (e && *e)) {
826 fprintf(stderr, "Invalid --version\n");
827 parse_error = 1;
828 }
829 break;
Bill Richardson72e344d2012-03-19 12:47:18 -0700830
Bill Richardson31d95c22014-08-24 22:07:17 -0700831 case OPT_MINVERSION:
832 min_version = strtoul(optarg, &e, 0);
833 if (!*optarg || (e && *e)) {
834 fprintf(stderr, "Invalid --minversion\n");
835 parse_error = 1;
836 }
837 break;
Bill Richardson72e344d2012-03-19 12:47:18 -0700838
Bill Richardson31d95c22014-08-24 22:07:17 -0700839 case OPT_PAD:
840 opt_pad = strtoul(optarg, &e, 0);
841 if (!*optarg || (e && *e)) {
842 fprintf(stderr, "Invalid --pad\n");
843 parse_error = 1;
844 }
845 break;
846 }
847 }
Bill Richardson72e344d2012-03-19 12:47:18 -0700848
Bill Richardson779796f2014-09-23 11:47:40 -0700849 if (parse_error) {
850 print_help(argv[0]);
851 return 1;
852 }
Bill Richardson72e344d2012-03-19 12:47:18 -0700853
Bill Richardson31d95c22014-08-24 22:07:17 -0700854 switch (mode) {
855 case OPT_MODE_PACK:
Bill Richardson72e344d2012-03-19 12:47:18 -0700856
Bill Richardson31d95c22014-08-24 22:07:17 -0700857 /* Required */
Bill Richardson72e344d2012-03-19 12:47:18 -0700858
Bill Richardson31d95c22014-08-24 22:07:17 -0700859 if (!keyblock_file)
860 Fatal("Missing required keyblock file.\n");
Bill Richardson72e344d2012-03-19 12:47:18 -0700861
Bill Richardson31d95c22014-08-24 22:07:17 -0700862 g_keyblock = (VbKeyBlockHeader *) ReadFile(keyblock_file, 0);
863 if (!g_keyblock)
864 Fatal("Error reading key block.\n");
Bill Richardson72e344d2012-03-19 12:47:18 -0700865
Bill Richardson31d95c22014-08-24 22:07:17 -0700866 if (!signprivkey_file)
867 Fatal("Missing required signprivate file.\n");
Bill Richardson72e344d2012-03-19 12:47:18 -0700868
Bill Richardson31d95c22014-08-24 22:07:17 -0700869 signpriv_key = PrivateKeyRead(signprivkey_file);
870 if (!signpriv_key)
871 Fatal("Error reading signing key.\n");
Bill Richardson72e344d2012-03-19 12:47:18 -0700872
Bill Richardson31d95c22014-08-24 22:07:17 -0700873 /* Optional */
Bill Richardson72e344d2012-03-19 12:47:18 -0700874
Bill Richardson31d95c22014-08-24 22:07:17 -0700875 if (config_file) {
876 Debug("Reading %s\n", config_file);
877 g_config_data =
Bill Richardson779796f2014-09-23 11:47:40 -0700878 sReadConfigFile(config_file, &g_config_size);
Bill Richardson31d95c22014-08-24 22:07:17 -0700879 if (!g_config_data)
880 Fatal("Error reading config file.\n");
881 }
Bill Richardson72e344d2012-03-19 12:47:18 -0700882
Bill Richardson31d95c22014-08-24 22:07:17 -0700883 if (vmlinuz_file)
884 if (!ImportVmlinuzFile
885 (vmlinuz_file, arch, kernel_body_load_address))
886 Fatal("Error reading kernel file.\n");
Bill Richardson72e344d2012-03-19 12:47:18 -0700887
Bill Richardson31d95c22014-08-24 22:07:17 -0700888 if (bootloader_file) {
889 Debug("Reading %s\n", bootloader_file);
890 g_bootloader_data =
891 ReadFile(bootloader_file, &g_bootloader_size);
892 if (!g_bootloader_data)
893 Fatal("Error reading bootloader file.\n");
894 Debug(" bootloader file size=0x%" PRIx64 "\n",
895 g_bootloader_size);
896 }
Bill Richardson72e344d2012-03-19 12:47:18 -0700897
Bill Richardson31d95c22014-08-24 22:07:17 -0700898 /* Do it */
899
Bill Richardson779796f2014-09-23 11:47:40 -0700900 kernel_blob = CreateKernBlob(kernel_body_load_address, arch,
901 &kernel_size);
Bill Richardson31d95c22014-08-24 22:07:17 -0700902
903 return Pack(filename, kernel_blob, kernel_size,
904 version, kernel_body_load_address, signpriv_key);
905
906 case OPT_MODE_REPACK:
907
908 /* Required */
909
910 if (!signprivkey_file)
911 Fatal("Missing required signprivate file.\n");
912
913 signpriv_key = PrivateKeyRead(signprivkey_file);
914 if (!signpriv_key)
915 Fatal("Error reading signing key.\n");
916
917 if (!oldfile)
918 Fatal("Missing previously packed blob.\n");
919
920 /* Load the old blob */
921
922 kernel_blob = ReadOldBlobFromFileOrDie(oldfile, &kernel_size);
923 if (0 != Verify(kernel_blob, kernel_size, 0, 0, 0))
924 Fatal("The oldblob doesn't verify\n");
925
926 /* Take it apart */
927
928 UnpackKernelBlob(kernel_blob, kernel_size);
929 free(kernel_blob);
930
931 /* Load optional params */
932
933 if (!version_str)
934 version = g_preamble->kernel_version;
935
936 if (!address_str)
937 kernel_body_load_address =
938 g_preamble->body_load_address;
939
940 if (config_file) {
941 if (g_config_data)
942 free(g_config_data);
943 Debug("Reading %s\n", config_file);
944 g_config_data =
Bill Richardson779796f2014-09-23 11:47:40 -0700945 sReadConfigFile(config_file, &g_config_size);
Bill Richardson31d95c22014-08-24 22:07:17 -0700946 if (!g_config_data)
947 Fatal("Error reading config file.\n");
948 }
949
950 if (keyblock_file) {
951 if (g_keyblock)
952 free(g_keyblock);
953 g_keyblock =
954 (VbKeyBlockHeader *) ReadFile(keyblock_file, 0);
955 if (!g_keyblock)
956 Fatal("Error reading key block.\n");
957 }
958
959 /* Put it back together */
960
Bill Richardson779796f2014-09-23 11:47:40 -0700961 kernel_blob = CreateKernBlob(kernel_body_load_address, arch,
962 &kernel_size);
Bill Richardson31d95c22014-08-24 22:07:17 -0700963
964 return Pack(filename, kernel_blob, kernel_size,
965 version, kernel_body_load_address, signpriv_key);
966
967 case OPT_MODE_VERIFY:
968
969 /* Optional */
970
971 if (signpubkey_file) {
972 signpub_key = PublicKeyRead(signpubkey_file);
973 if (!signpub_key)
974 Fatal("Error reading public key.\n");
975 }
976
977 /* Do it */
978
979 kernel_blob = ReadOldBlobFromFileOrDie(filename, &kernel_size);
980
981 return Verify(kernel_blob, kernel_size, signpub_key,
982 keyblock_file, min_version);
983 }
984
985 fprintf(stderr,
986 "You must specify a mode: --pack, --repack or --verify\n");
Bill Richardson779796f2014-09-23 11:47:40 -0700987 print_help(argv[0]);
988 return 1;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700989}
Bill Richardson6f396152014-07-15 12:52:19 -0700990
991DECLARE_FUTIL_COMMAND(vbutil_kernel, do_vbutil_kernel,
Bill Richardson779796f2014-09-23 11:47:40 -0700992 "Creates, signs, and verifies the kernel blob",
993 print_help);