blob: 85f8a5143afb6f305431b39d0ecb05ac2d93a32e [file] [log] [blame]
Randall Spangler7d6898d2010-06-11 09:22:13 -07001/* Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
2 * 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>
Randall Spangler7d6898d2010-06-11 09:22:13 -07009#include <getopt.h>
10#include <inttypes.h> /* For PRIu64 */
Bill Richardson249677d2010-06-23 11:16:37 -070011#include <stdarg.h>
Randall Spangler7d6898d2010-06-11 09:22:13 -070012#include <stddef.h>
13#include <stdio.h>
14#include <stdlib.h>
Bill Richardsona08b5c92010-06-30 21:59:43 -070015#include <string.h>
16#include <sys/stat.h>
17#include <sys/types.h>
Randall Spangler7d6898d2010-06-11 09:22:13 -070018#include <unistd.h>
19
20#include "cryptolib.h"
21#include "host_common.h"
22#include "kernel_blob.h"
23#include "vboot_common.h"
24
25
Bill Richardson249677d2010-06-23 11:16:37 -070026/* Global opt */
27static int opt_debug = 0;
28
Bill Richardsona08b5c92010-06-30 21:59:43 -070029static const int DEFAULT_PADDING = 65536;
Bill Richardson249677d2010-06-23 11:16:37 -070030
Randall Spangler7d6898d2010-06-11 09:22:13 -070031/* Command line options */
32enum {
33 OPT_MODE_PACK = 1000,
Bill Richardsona08b5c92010-06-30 21:59:43 -070034 OPT_MODE_REPACK,
Randall Spangler7d6898d2010-06-11 09:22:13 -070035 OPT_MODE_VERIFY,
Che-Liang Chiou03762032011-02-22 11:16:51 +080036 OPT_ARCH,
Bill Richardsona08b5c92010-06-30 21:59:43 -070037 OPT_OLDBLOB,
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +080038 OPT_KLOADADDR,
Randall Spangler7d6898d2010-06-11 09:22:13 -070039 OPT_KEYBLOCK,
40 OPT_SIGNPUBKEY,
41 OPT_SIGNPRIVATE,
42 OPT_VERSION,
43 OPT_VMLINUZ,
44 OPT_BOOTLOADER,
45 OPT_CONFIG,
Bill Richardsona08b5c92010-06-30 21:59:43 -070046 OPT_VBLOCKONLY,
Randall Spangler7d6898d2010-06-11 09:22:13 -070047 OPT_PAD,
vbendebb2b0fcc2010-07-15 15:09:47 -070048 OPT_VERBOSE,
Randall Spangler7d6898d2010-06-11 09:22:13 -070049};
50
Che-Liang Chiou03762032011-02-22 11:16:51 +080051enum {
52 ARCH_ARM,
53 ARCH_X86 /* default */
54};
55
Randall Spangler7d6898d2010-06-11 09:22:13 -070056static struct option long_opts[] = {
57 {"pack", 1, 0, OPT_MODE_PACK },
Bill Richardsona08b5c92010-06-30 21:59:43 -070058 {"repack", 1, 0, OPT_MODE_REPACK },
Randall Spangler7d6898d2010-06-11 09:22:13 -070059 {"verify", 1, 0, OPT_MODE_VERIFY },
Che-Liang Chiou03762032011-02-22 11:16:51 +080060 {"arch", 1, 0, OPT_ARCH },
Bill Richardsona08b5c92010-06-30 21:59:43 -070061 {"oldblob", 1, 0, OPT_OLDBLOB },
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +080062 {"kloadaddr", 1, 0, OPT_KLOADADDR },
Randall Spangler7d6898d2010-06-11 09:22:13 -070063 {"keyblock", 1, 0, OPT_KEYBLOCK },
64 {"signpubkey", 1, 0, OPT_SIGNPUBKEY },
65 {"signprivate", 1, 0, OPT_SIGNPRIVATE },
66 {"version", 1, 0, OPT_VERSION },
67 {"vmlinuz", 1, 0, OPT_VMLINUZ },
68 {"bootloader", 1, 0, OPT_BOOTLOADER },
69 {"config", 1, 0, OPT_CONFIG },
Bill Richardsona08b5c92010-06-30 21:59:43 -070070 {"vblockonly", 0, 0, OPT_VBLOCKONLY },
Randall Spangler7d6898d2010-06-11 09:22:13 -070071 {"pad", 1, 0, OPT_PAD },
vbendebb2b0fcc2010-07-15 15:09:47 -070072 {"verbose", 0, 0, OPT_VERBOSE },
Bill Richardson249677d2010-06-23 11:16:37 -070073 {"debug", 0, &opt_debug, 1 },
Randall Spangler7d6898d2010-06-11 09:22:13 -070074 {NULL, 0, 0, 0}
75};
76
77
78/* Print help and return error */
Bill Richardsona08b5c92010-06-30 21:59:43 -070079static int PrintHelp(char *progname) {
80 fprintf(stderr,
81 "This program creates, signs, and verifies the kernel blob\n");
82 fprintf(stderr,
83 "\n"
84 "Usage: %s --pack <file> [PARAMETERS]\n"
85 "\n"
86 " Required parameters:\n"
87 " --keyblock <file> Key block in .keyblock format\n"
Bill Richardson4f36ef32010-08-09 17:50:14 -070088 " --signprivate <file>"
89 " Private key to sign kernel data, in .vbprivk format\n"
Bill Richardsona08b5c92010-06-30 21:59:43 -070090 " --version <number> Kernel version\n"
91 " --vmlinuz <file> Linux kernel bzImage file\n"
92 " --bootloader <file> Bootloader stub\n"
vbendebb2b0fcc2010-07-15 15:09:47 -070093 " --config <file> Command line file\n"
Che-Liang Chiou03762032011-02-22 11:16:51 +080094 " --arch <arch> Cpu architecture (default x86)\n"
Bill Richardsona08b5c92010-06-30 21:59:43 -070095 "\n"
96 " Optional:\n"
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +080097 " --kloadaddr <address> Assign kernel body load address\n"
Bill Richardsona08b5c92010-06-30 21:59:43 -070098 " --pad <number> Verification padding size in bytes\n"
99 " --vblockonly Emit just the verification blob\n",
100 progname);
101 fprintf(stderr,
102 "\nOR\n\n"
103 "Usage: %s --repack <file> [PARAMETERS]\n"
104 "\n"
vbendeb858fffb2010-10-06 09:51:44 -0700105 " Required parameters (of --keyblock, --config, and --version \n"
106 " at least one is required):\n"
Bill Richardsona08b5c92010-06-30 21:59:43 -0700107 " --keyblock <file> Key block in .keyblock format\n"
Bill Richardson4f36ef32010-08-09 17:50:14 -0700108 " --signprivate <file>"
109 " Private key to sign kernel data, in .vbprivk format\n"
Bill Richardsona08b5c92010-06-30 21:59:43 -0700110 " --oldblob <file> Previously packed kernel blob\n"
vbendebb2b0fcc2010-07-15 15:09:47 -0700111 " --config <file> New command line file\n"
vbendeb858fffb2010-10-06 09:51:44 -0700112 " --version <number> Kernel version\n"
Bill Richardsona08b5c92010-06-30 21:59:43 -0700113 "\n"
114 " Optional:\n"
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +0800115 " --kloadaddr <address> Assign kernel body load address\n"
Bill Richardsona08b5c92010-06-30 21:59:43 -0700116 " --pad <number> Verification padding size in bytes\n"
117 " --vblockonly Emit just the verification blob\n",
118 progname);
119 fprintf(stderr,
120 "\nOR\n\n"
121 "Usage: %s --verify <file> [PARAMETERS]\n"
122 "\n"
vbendebb2b0fcc2010-07-15 15:09:47 -0700123 " Optional:\n"
Bill Richardson4f36ef32010-08-09 17:50:14 -0700124 " --signpubkey <file>"
125 " Public key to verify kernel keyblock, in .vbpubk format\n"
vbendebb2b0fcc2010-07-15 15:09:47 -0700126 " --verbose Print a more detailed report\n"
Will Drewry9342f882010-10-26 10:22:05 -0500127 " --keyblock <file>"
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +0800128 " Outputs the verified key block, in .keyblock format\n"
129 " --kloadaddr <address> Assign kernel body load address\n"
Bill Richardsona08b5c92010-06-30 21:59:43 -0700130 "\n",
131 progname);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700132 return 1;
133}
134
Bill Richardson249677d2010-06-23 11:16:37 -0700135static void Debug(const char *format, ...) {
136 if (!opt_debug)
137 return;
138
139 va_list ap;
140 va_start(ap, format);
141 fprintf(stderr, "DEBUG: ");
142 vfprintf(stderr, format, ap);
143 va_end(ap);
144}
145
Bill Richardson2f6a71f2010-10-14 09:25:39 -0700146/* Return an explanation when fread() fails. */
147static const char *error_fread(FILE *fp) {
148 const char *retval = "beats me why";
149 if (feof(fp))
150 retval = "EOF";
151 else if (ferror(fp))
152 retval = strerror(errno);
153 clearerr(fp);
154 return retval;
155}
Randall Spangler7d6898d2010-06-11 09:22:13 -0700156
157/* Return the smallest integral multiple of [alignment] that is equal
158 * to or greater than [val]. Used to determine the number of
159 * pages/sectors/blocks/whatever needed to contain [val]
160 * items/bytes/etc. */
161static uint64_t roundup(uint64_t val, uint64_t alignment) {
162 uint64_t rem = val % alignment;
163 if ( rem )
164 return val + (alignment - rem);
165 return val;
166}
167
168
169/* Match regexp /\b--\b/ to delimit the start of the kernel commandline. If we
170 * don't find one, we'll use the whole thing. */
171static unsigned int find_cmdline_start(char *input, unsigned int max_len) {
172 int start = 0;
173 int i;
174 for(i = 0; i < max_len - 1 && input[i]; i++) {
175 if ('-' == input[i] && '-' == input[i + 1]) { /* found a "--" */
176 if ((i == 0 || ' ' == input[i - 1]) && /* nothing before it */
177 (i + 2 >= max_len || ' ' == input[i+2])) { /* nothing after it */
178 start = i+2; /* note: hope there's a trailing '\0' */
179 break;
180 }
181 }
182 }
183 while(' ' == input[start]) /* skip leading spaces */
184 start++;
185
186 return start;
187}
188
189
Bill Richardsona08b5c92010-06-30 21:59:43 -0700190typedef struct blob_s {
191 /* Stuff needed by VbKernelPreambleHeader */
192 uint64_t kernel_version;
193 uint64_t bootloader_address;
194 uint64_t bootloader_size;
195 /* Raw kernel blob data */
196 uint64_t blob_size;
197 uint8_t *blob;
vbendebb2b0fcc2010-07-15 15:09:47 -0700198
199 /* these fields are not always initialized */
200 VbKernelPreambleHeader* preamble;
201 VbKeyBlockHeader* key_block;
202 uint8_t *buf;
203
Bill Richardsona08b5c92010-06-30 21:59:43 -0700204} blob_t;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700205
vbendebb2b0fcc2010-07-15 15:09:47 -0700206/* Given a blob return the location of the kernel command line buffer. */
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +0800207static char* BpCmdLineLocation(blob_t *bp, uint64_t kernel_body_load_address)
vbendebb2b0fcc2010-07-15 15:09:47 -0700208{
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +0800209 return (char*)(bp->blob + bp->bootloader_address - kernel_body_load_address -
vbendebb2b0fcc2010-07-15 15:09:47 -0700210 CROS_CONFIG_SIZE - CROS_PARAMS_SIZE);
211}
Bill Richardsona08b5c92010-06-30 21:59:43 -0700212
213static void FreeBlob(blob_t *bp) {
214 if (bp) {
215 if (bp->blob)
216 Free(bp->blob);
vbendebb2b0fcc2010-07-15 15:09:47 -0700217 if (bp->buf)
218 Free(bp->buf);
Bill Richardsona08b5c92010-06-30 21:59:43 -0700219 Free(bp);
220 }
221}
222
vbendebb2b0fcc2010-07-15 15:09:47 -0700223/*
224 * Read the kernel command line from a file. Get rid of \n characters along
225 * the way and verify that the line fits into a 4K buffer.
226 *
227 * Return the buffer contaning the line on success (and set the line length
228 * using the passed in parameter), or NULL in case something goes wrong.
229 */
230static uint8_t* ReadConfigFile(const char* config_file, uint64_t* config_size)
231{
232 uint8_t* config_buf;
233 int ii;
234
235 config_buf = ReadFile(config_file, config_size);
236 Debug(" config file size=0x%" PRIx64 "\n", *config_size);
237 if (CROS_CONFIG_SIZE <= *config_size) { /* need room for trailing '\0' */
238 error("Config file %s is too large (>= %d bytes)\n",
239 config_file, CROS_CONFIG_SIZE);
240 return NULL;
241 }
242
243 /* Replace newlines with spaces */
244 for (ii = 0; ii < *config_size; ii++) {
245 if ('\n' == config_buf[ii]) {
246 config_buf[ii] = ' ';
247 }
248 }
249 return config_buf;
250}
251
Bill Richardsona08b5c92010-06-30 21:59:43 -0700252/* Create a blob from its components */
253static blob_t *NewBlob(uint64_t version,
254 const char* vmlinuz,
255 const char* bootloader_file,
Che-Liang Chiou03762032011-02-22 11:16:51 +0800256 const char* config_file,
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +0800257 int arch,
258 uint64_t kernel_body_load_address) {
Che-Liang Chiou03762032011-02-22 11:16:51 +0800259 blob_t* bp;
260 struct linux_kernel_header* lh = 0;
261 struct linux_kernel_params* params = 0;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700262 uint8_t* config_buf;
263 uint64_t config_size;
264 uint8_t* bootloader_buf;
265 uint64_t bootloader_size;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700266 uint8_t* kernel_buf;
267 uint64_t kernel_size;
268 uint64_t kernel32_start = 0;
269 uint64_t kernel32_size = 0;
270 uint32_t cmdline_addr;
271 uint8_t* blob = NULL;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700272 uint64_t now = 0;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700273
Randall Spangler7d6898d2010-06-11 09:22:13 -0700274 if (!vmlinuz || !bootloader_file || !config_file) {
275 error("Must specify all input files\n");
Bill Richardsona08b5c92010-06-30 21:59:43 -0700276 return 0;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700277 }
278
Bill Richardsona08b5c92010-06-30 21:59:43 -0700279 bp = (blob_t *)Malloc(sizeof(blob_t));
280 if (!bp) {
281 error("Couldn't allocate bytes for blob_t.\n");
282 return 0;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700283 }
vbendebb2b0fcc2010-07-15 15:09:47 -0700284
285 Memset(bp, 0, sizeof(*bp));
Bill Richardsona08b5c92010-06-30 21:59:43 -0700286 bp->kernel_version = version;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700287
288 /* Read the config file */
Bill Richardson249677d2010-06-23 11:16:37 -0700289 Debug("Reading %s\n", config_file);
vbendebb2b0fcc2010-07-15 15:09:47 -0700290 config_buf = ReadConfigFile(config_file, &config_size);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700291 if (!config_buf)
Bill Richardsona08b5c92010-06-30 21:59:43 -0700292 return 0;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700293
294 /* Read the bootloader */
Bill Richardson249677d2010-06-23 11:16:37 -0700295 Debug("Reading %s\n", bootloader_file);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700296 bootloader_buf = ReadFile(bootloader_file, &bootloader_size);
297 if (!bootloader_buf)
Bill Richardsona08b5c92010-06-30 21:59:43 -0700298 return 0;
Bill Richardson249677d2010-06-23 11:16:37 -0700299 Debug(" bootloader file size=0x%" PRIx64 "\n", bootloader_size);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700300
301 /* Read the kernel */
Bill Richardson249677d2010-06-23 11:16:37 -0700302 Debug("Reading %s\n", vmlinuz);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700303 kernel_buf = ReadFile(vmlinuz, &kernel_size);
304 if (!kernel_buf)
Bill Richardsona08b5c92010-06-30 21:59:43 -0700305 return 0;
Bill Richardson249677d2010-06-23 11:16:37 -0700306 Debug(" kernel file size=0x%" PRIx64 "\n", kernel_size);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700307 if (!kernel_size) {
308 error("Empty kernel file\n");
Bill Richardsona08b5c92010-06-30 21:59:43 -0700309 return 0;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700310 }
311
Che-Liang Chiou03762032011-02-22 11:16:51 +0800312 if (arch == ARCH_X86) {
313 /* The first part of vmlinuz is a header, followed by a real-mode
314 * boot stub. We only want the 32-bit part. */
315 lh = (struct linux_kernel_header *)kernel_buf;
316 kernel32_start = (lh->setup_sects + 1) << 9;
317 if (kernel32_start >= kernel_size) {
318 error("Malformed kernel\n");
319 return 0;
320 }
321 } else
322 kernel32_start = 0;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700323 kernel32_size = kernel_size - kernel32_start;
Bill Richardson249677d2010-06-23 11:16:37 -0700324 Debug(" kernel32_start=0x%" PRIx64 "\n", kernel32_start);
325 Debug(" kernel32_size=0x%" PRIx64 "\n", kernel32_size);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700326
327 /* Allocate and zero the blob we need. */
Bill Richardsona08b5c92010-06-30 21:59:43 -0700328 bp->blob_size = roundup(kernel32_size, CROS_ALIGN) +
Randall Spangler7d6898d2010-06-11 09:22:13 -0700329 CROS_CONFIG_SIZE +
330 CROS_PARAMS_SIZE +
331 roundup(bootloader_size, CROS_ALIGN);
Bill Richardsona08b5c92010-06-30 21:59:43 -0700332 blob = (uint8_t *)Malloc(bp->blob_size);
333 Debug("blob_size=0x%" PRIx64 "\n", bp->blob_size);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700334 if (!blob) {
Bill Richardsona08b5c92010-06-30 21:59:43 -0700335 error("Couldn't allocate %ld bytes.\n", bp->blob_size);
336 return 0;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700337 }
Bill Richardsona08b5c92010-06-30 21:59:43 -0700338 Memset(blob, 0, bp->blob_size);
339 bp->blob = blob;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700340
341 /* Copy the 32-bit kernel. */
Bill Richardson249677d2010-06-23 11:16:37 -0700342 Debug("kernel goes at blob+=0x%" PRIx64 "\n", now);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700343 if (kernel32_size)
344 Memcpy(blob + now, kernel_buf + kernel32_start, kernel32_size);
345 now += roundup(now + kernel32_size, CROS_ALIGN);
346
Bill Richardson249677d2010-06-23 11:16:37 -0700347 Debug("config goes at blob+0x%" PRIx64 "\n", now);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700348 /* Find the load address of the commandline. We'll need it later. */
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +0800349 cmdline_addr = kernel_body_load_address + now +
Randall Spangler7d6898d2010-06-11 09:22:13 -0700350 find_cmdline_start((char *)config_buf, config_size);
Bill Richardson249677d2010-06-23 11:16:37 -0700351 Debug(" cmdline_addr=0x%" PRIx64 "\n", cmdline_addr);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700352
353 /* Copy the config. */
354 if (config_size)
355 Memcpy(blob + now, config_buf, config_size);
356 now += CROS_CONFIG_SIZE;
357
358 /* The zeropage data is next. Overlay the linux_kernel_header onto it, and
359 * tweak a few fields. */
Bill Richardson249677d2010-06-23 11:16:37 -0700360 Debug("params goes at blob+=0x%" PRIx64 "\n", now);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700361 params = (struct linux_kernel_params *)(blob + now);
Che-Liang Chiou03762032011-02-22 11:16:51 +0800362 if (arch == ARCH_X86)
363 Memcpy(&(params->setup_sects), &(lh->setup_sects),
364 sizeof(*lh) - offsetof(struct linux_kernel_header, setup_sects));
365 else
366 Memset(&(params->setup_sects), 0,
367 sizeof(*lh) - offsetof(struct linux_kernel_header, setup_sects));
Randall Spangler7d6898d2010-06-11 09:22:13 -0700368 params->boot_flag = 0;
369 params->ramdisk_image = 0; /* we don't support initrd */
370 params->ramdisk_size = 0;
371 params->type_of_loader = 0xff;
372 params->cmd_line_ptr = cmdline_addr;
Che-Liang Chiou475bf442010-08-23 11:20:44 +0800373 /* A fake e820 memory map with 2 entries */
374 params->n_e820_entry = 2;
375 params->e820_entries[0].start_addr = 0x00000000;
376 params->e820_entries[0].segment_size = 0x00001000;
377 params->e820_entries[0].segment_type = E820_TYPE_RAM;
378 params->e820_entries[1].start_addr = 0xfffff000;
379 params->e820_entries[1].segment_size = 0x00001000;
380 params->e820_entries[1].segment_type = E820_TYPE_RESERVED;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700381 now += CROS_PARAMS_SIZE;
382
383 /* Finally, append the bootloader. Remember where it will load in
384 * memory, too. */
Bill Richardson249677d2010-06-23 11:16:37 -0700385 Debug("bootloader goes at blob+=0x%" PRIx64 "\n", now);
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +0800386 bp->bootloader_address = kernel_body_load_address + now;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700387 bp->bootloader_size = roundup(bootloader_size, CROS_ALIGN);
388 Debug(" bootloader_address=0x%" PRIx64 "\n", bp->bootloader_address);
389 Debug(" bootloader_size=0x%" PRIx64 "\n", bp->bootloader_size);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700390 if (bootloader_size)
391 Memcpy(blob + now, bootloader_buf, bootloader_size);
Bill Richardsona08b5c92010-06-30 21:59:43 -0700392 now += bp->bootloader_size;
Bill Richardson249677d2010-06-23 11:16:37 -0700393 Debug("end of blob is 0x%" PRIx64 "\n", now);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700394
395 /* Free input buffers */
396 Free(kernel_buf);
397 Free(config_buf);
398 Free(bootloader_buf);
399
Bill Richardsona08b5c92010-06-30 21:59:43 -0700400 /* Success */
401 return bp;
402}
403
404
405/* Pull the blob_t stuff out of a prepacked kernel blob file */
406static blob_t *OldBlob(const char* filename) {
vbendebb2b0fcc2010-07-15 15:09:47 -0700407 FILE* fp = NULL;
408 blob_t *bp = NULL;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700409 struct stat statbuf;
410 VbKeyBlockHeader* key_block;
411 VbKernelPreambleHeader* preamble;
412 uint64_t now = 0;
vbendebb2b0fcc2010-07-15 15:09:47 -0700413 uint8_t* buf = NULL;
414 int ret_error = 1;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700415
416 if (!filename) {
417 error("Must specify prepacked blob to read\n");
418 return 0;
419 }
420
421 if (0 != stat(filename, &statbuf)) {
Bill Richardson2f6a71f2010-10-14 09:25:39 -0700422 error("Unable to stat %s: %s\n", filename, strerror(errno));
Bill Richardsona08b5c92010-06-30 21:59:43 -0700423 return 0;
424 }
425
426 Debug("%s size is 0x%" PRIx64 "\n", filename, statbuf.st_size);
427 if (statbuf.st_size < DEFAULT_PADDING) {
428 error("%s is too small to be a valid kernel blob\n");
429 return 0;
430 }
431
432 Debug("Reading %s\n", filename);
433 fp = fopen(filename, "rb");
434 if (!fp) {
435 error("Unable to open file %s: %s\n", filename, strerror(errno));
436 return 0;
437 }
438
vbendebb2b0fcc2010-07-15 15:09:47 -0700439 buf = Malloc(DEFAULT_PADDING);
440 if (!buf) {
441 error("Unable to allocate padding\n");
442 goto unwind_oldblob;
443 }
444
445 if (1 != fread(buf, DEFAULT_PADDING, 1, fp)) {
Bill Richardson2f6a71f2010-10-14 09:25:39 -0700446 error("Unable to read header from %s: %s\n", filename, error_fread(fp));
vbendebb2b0fcc2010-07-15 15:09:47 -0700447 goto unwind_oldblob;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700448 }
449
450 /* Skip the key block */
451 key_block = (VbKeyBlockHeader*)buf;
452 Debug("Keyblock is 0x%" PRIx64 " bytes\n", key_block->key_block_size);
453 now += key_block->key_block_size;
454 if (now > statbuf.st_size) {
455 error("key_block_size advances past the end of the blob\n");
vbendebb2b0fcc2010-07-15 15:09:47 -0700456 goto unwind_oldblob;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700457 }
458
459 /* Skip the preamble */
460 preamble = (VbKernelPreambleHeader*)(buf + now);
461 Debug("Preamble is 0x%" PRIx64 " bytes\n", preamble->preamble_size);
462 now += preamble->preamble_size;
463 if (now > statbuf.st_size) {
464 error("preamble_size advances past the end of the blob\n");
vbendebb2b0fcc2010-07-15 15:09:47 -0700465 goto unwind_oldblob;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700466 }
467
468 /* Go find the kernel blob */
469 Debug("kernel blob is at offset 0x%" PRIx64 "\n", now);
470 if (0 != fseek(fp, now, SEEK_SET)) {
471 error("Unable to seek to 0x%" PRIx64 " in %s: %s\n", now, filename,
472 strerror(errno));
vbendebb2b0fcc2010-07-15 15:09:47 -0700473 goto unwind_oldblob;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700474 }
475
476 /* Remember what we've got */
477 bp = (blob_t *)Malloc(sizeof(blob_t));
478 if (!bp) {
479 error("Couldn't allocate bytes for blob_t.\n");
vbendebb2b0fcc2010-07-15 15:09:47 -0700480 goto unwind_oldblob;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700481 }
482
vbendebb2b0fcc2010-07-15 15:09:47 -0700483 bp->buf = buf;
484 bp->key_block = key_block;
485 bp->preamble = preamble;
486
Bill Richardsona08b5c92010-06-30 21:59:43 -0700487 bp->kernel_version = preamble->kernel_version;
488 bp->bootloader_address = preamble->bootloader_address;
489 bp->bootloader_size = preamble->bootloader_size;
490 bp->blob_size = preamble->body_signature.data_size;
491
492 Debug(" kernel_version = %d\n", bp->kernel_version);
493 Debug(" bootloader_address = 0x%" PRIx64 "\n", bp->bootloader_address);
494 Debug(" bootloader_size = 0x%" PRIx64 "\n", bp->bootloader_size);
495 Debug(" blob_size = 0x%" PRIx64 "\n", bp->blob_size);
496
Bill Richardson2f6a71f2010-10-14 09:25:39 -0700497 if (!bp->blob_size) {
498 error("No kernel blob found\n");
499 goto unwind_oldblob;
500 }
501
Bill Richardsona08b5c92010-06-30 21:59:43 -0700502 bp->blob = (uint8_t *)Malloc(bp->blob_size);
503 if (!bp->blob) {
504 error("Couldn't allocate 0x%" PRIx64 " bytes for blob_t.\n", bp->blob_size);
vbendebb2b0fcc2010-07-15 15:09:47 -0700505 goto unwind_oldblob;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700506 }
507
508 /* read it in */
509 if (1 != fread(bp->blob, bp->blob_size, 1, fp)) {
Bill Richardson2f6a71f2010-10-14 09:25:39 -0700510 error("Unable to read kernel blob from %s: %s\n", filename, error_fread(fp));
vbendebb2b0fcc2010-07-15 15:09:47 -0700511 goto unwind_oldblob;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700512 }
513
vbendebb2b0fcc2010-07-15 15:09:47 -0700514 ret_error = 0;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700515
vbendebb2b0fcc2010-07-15 15:09:47 -0700516 /* done */
517unwind_oldblob:
518 fclose(fp);
519 if (ret_error) {
520 if (bp) {
521 FreeBlob(bp);
522 bp = NULL;
523 } else if (buf) {
524 Free(buf);
525 }
526 }
Bill Richardsona08b5c92010-06-30 21:59:43 -0700527 return bp;
528}
529
530
531/* Pack a .kernel */
532static int Pack(const char* outfile, const char* keyblock_file,
533 const char* signprivate, blob_t *bp, uint64_t pad,
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +0800534 int vblockonly,
535 uint64_t kernel_body_load_address) {
Bill Richardsona08b5c92010-06-30 21:59:43 -0700536 VbPrivateKey* signing_key;
537 VbSignature* body_sig;
538 VbKernelPreambleHeader* preamble;
539 VbKeyBlockHeader* key_block;
540 uint64_t key_block_size;
541 FILE* f;
542 uint64_t i;
543
544 if (!outfile) {
545 error("Must specify output filename\n");
546 return 1;
547 }
vbendebb2b0fcc2010-07-15 15:09:47 -0700548 if ((!keyblock_file && !bp->key_block) || !signprivate) {
Bill Richardsona08b5c92010-06-30 21:59:43 -0700549 error("Must specify all keys\n");
550 return 1;
551 }
552 if (!bp) {
553 error("Refusing to pack invalid kernel blob\n");
554 return 1;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700555 }
vbendebb2b0fcc2010-07-15 15:09:47 -0700556
557 /* Get the key block and read the private key. */
558 if (keyblock_file) {
559 key_block = (VbKeyBlockHeader*)ReadFile(keyblock_file, &key_block_size);
560 if (!key_block) {
561 error("Error reading key block.\n");
562 return 1;
563 }
564 } else {
565 key_block = bp->key_block;
566 key_block_size = key_block->key_block_size;
567 }
568
Bill Richardsona08b5c92010-06-30 21:59:43 -0700569 if (pad < key_block->key_block_size) {
570 error("Pad too small\n");
571 return 1;
572 }
573
Bill Richardsonabf05502010-07-01 10:22:06 -0700574 signing_key = PrivateKeyRead(signprivate);
Bill Richardsona08b5c92010-06-30 21:59:43 -0700575 if (!signing_key) {
576 error("Error reading signing key.\n");
577 return 1;
578 }
579
Randall Spangler7d6898d2010-06-11 09:22:13 -0700580 /* Sign the kernel data */
Bill Richardsona08b5c92010-06-30 21:59:43 -0700581 body_sig = CalculateSignature(bp->blob, bp->blob_size, signing_key);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700582 if (!body_sig) {
583 error("Error calculating body signature\n");
584 return 1;
585 }
586
587 /* Create preamble */
Bill Richardsona08b5c92010-06-30 21:59:43 -0700588 preamble = CreateKernelPreamble(bp->kernel_version,
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +0800589 kernel_body_load_address,
Bill Richardsona08b5c92010-06-30 21:59:43 -0700590 bp->bootloader_address,
591 bp->bootloader_size,
Randall Spangler7d6898d2010-06-11 09:22:13 -0700592 body_sig,
593 pad - key_block_size,
594 signing_key);
595 if (!preamble) {
596 error("Error creating preamble.\n");
597 return 1;
598 }
599
600 /* Write the output file */
Bill Richardson249677d2010-06-23 11:16:37 -0700601 Debug("writing %s...\n", outfile);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700602 f = fopen(outfile, "wb");
603 if (!f) {
604 error("Can't open output file %s\n", outfile);
605 return 1;
606 }
Bill Richardson249677d2010-06-23 11:16:37 -0700607 Debug("0x%" PRIx64 " bytes of key_block\n", key_block_size);
608 Debug("0x%" PRIx64 " bytes of preamble\n", preamble->preamble_size);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700609 i = ((1 != fwrite(key_block, key_block_size, 1, f)) ||
Bill Richardsona08b5c92010-06-30 21:59:43 -0700610 (1 != fwrite(preamble, preamble->preamble_size, 1, f)));
Randall Spangler7d6898d2010-06-11 09:22:13 -0700611 if (i) {
612 error("Can't write output file %s\n", outfile);
Bill Richardsona08b5c92010-06-30 21:59:43 -0700613 fclose(f);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700614 unlink(outfile);
615 return 1;
616 }
617
Bill Richardsona08b5c92010-06-30 21:59:43 -0700618 if (!vblockonly) {
619 Debug("0x%" PRIx64 " bytes of blob\n", bp->blob_size);
620 i = (1 != fwrite(bp->blob, bp->blob_size, 1, f));
621 if (i) {
622 error("Can't write output file %s\n", outfile);
623 fclose(f);
624 unlink(outfile);
625 return 1;
626 }
627 }
628
629 fclose(f);
630
Randall Spangler7d6898d2010-06-11 09:22:13 -0700631 /* Success */
632 return 0;
633}
634
vbendebb2b0fcc2010-07-15 15:09:47 -0700635/*
636 * Replace kernel command line in a blob representing a kernel.
637 */
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +0800638static int ReplaceConfig(blob_t* bp, const char* config_file,
639 uint64_t kernel_body_load_address)
vbendebb2b0fcc2010-07-15 15:09:47 -0700640{
641 uint8_t* new_conf;
642 uint64_t config_size;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700643
vbendebb2b0fcc2010-07-15 15:09:47 -0700644 if (!config_file) {
645 return 0;
646 }
647
648 new_conf = ReadConfigFile(config_file, &config_size);
649 if (!new_conf) {
650 return 1;
651 }
652
653 /* fill the config buffer with zeros */
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +0800654 Memset(BpCmdLineLocation(bp, kernel_body_load_address), 0, CROS_CONFIG_SIZE);
655 Memcpy(BpCmdLineLocation(bp, kernel_body_load_address),
656 new_conf, config_size);
vbendebb2b0fcc2010-07-15 15:09:47 -0700657 Free(new_conf);
658 return 0;
659}
660
Will Drewry9342f882010-10-26 10:22:05 -0500661static int Verify(const char* infile, const char* signpubkey, int verbose,
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +0800662 const char* key_block_file,
663 uint64_t kernel_body_load_address) {
Randall Spangler7d6898d2010-06-11 09:22:13 -0700664
665 VbKeyBlockHeader* key_block;
666 VbKernelPreambleHeader* preamble;
667 VbPublicKey* data_key;
Bill Richardson4f36ef32010-08-09 17:50:14 -0700668 VbPublicKey* sign_key = NULL;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700669 RSAPublicKey* rsa;
vbendebb2b0fcc2010-07-15 15:09:47 -0700670 blob_t* bp;
671 uint64_t now;
672 int rv = 1;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700673
Bill Richardson4f36ef32010-08-09 17:50:14 -0700674 if (!infile) {
675 error("Must specify filename\n");
Randall Spangler7d6898d2010-06-11 09:22:13 -0700676 return 1;
677 }
678
679 /* Read public signing key */
Bill Richardson4f36ef32010-08-09 17:50:14 -0700680 if (signpubkey) {
681 sign_key = PublicKeyRead(signpubkey);
682 if (!sign_key) {
683 error("Error reading signpubkey.\n");
684 return 1;
685 }
Randall Spangler7d6898d2010-06-11 09:22:13 -0700686 }
687
688 /* Read blob */
vbendebb2b0fcc2010-07-15 15:09:47 -0700689 bp = OldBlob(infile);
690 if (!bp) {
Randall Spangler7d6898d2010-06-11 09:22:13 -0700691 error("Error reading input file\n");
692 return 1;
693 }
694
695 /* Verify key block */
vbendebb2b0fcc2010-07-15 15:09:47 -0700696 key_block = bp->key_block;
Randall Spangler138acfe2010-08-17 15:45:21 -0700697 if (0 != KeyBlockVerify(key_block, bp->blob_size, sign_key,
698 (sign_key ? 0 : 1))) {
Randall Spangler7d6898d2010-06-11 09:22:13 -0700699 error("Error verifying key block.\n");
vbendebb2b0fcc2010-07-15 15:09:47 -0700700 goto verify_exit;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700701 }
vbendebb2b0fcc2010-07-15 15:09:47 -0700702 now = key_block->key_block_size;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700703
Will Drewry9342f882010-10-26 10:22:05 -0500704 if (key_block_file) {
705 FILE* f = NULL;
706 f = fopen(key_block_file, "wb");
707 if (!f) {
708 error("Can't open key block file %s\n", key_block_file);
709 return 1;
710 }
711 if (1 != fwrite(key_block, key_block->key_block_size, 1, f)) {
712 error("Can't write key block file %s\n", key_block_file);
713 return 1;
714 }
715 fclose(f);
716 }
717
Randall Spangler7d6898d2010-06-11 09:22:13 -0700718 printf("Key block:\n");
719 data_key = &key_block->data_key;
Bill Richardson4f36ef32010-08-09 17:50:14 -0700720 if (verbose)
721 printf(" Signature: %s\n", sign_key ? "valid" : "ignored");
Bill Richardsona08b5c92010-06-30 21:59:43 -0700722 printf(" Size: 0x%" PRIx64 "\n", key_block->key_block_size);
Bill Richardson60bcbe32010-09-09 14:53:56 -0700723 printf(" Flags: %" PRIu64 " ", key_block->key_block_flags);
724 if (key_block->key_block_flags & KEY_BLOCK_FLAG_DEVELOPER_0)
725 printf(" !DEV");
726 if (key_block->key_block_flags & KEY_BLOCK_FLAG_DEVELOPER_1)
727 printf(" DEV");
728 if (key_block->key_block_flags & KEY_BLOCK_FLAG_RECOVERY_0)
729 printf(" !REC");
730 if (key_block->key_block_flags & KEY_BLOCK_FLAG_RECOVERY_1)
731 printf(" REC");
732 printf("\n");
Randall Spangler7d6898d2010-06-11 09:22:13 -0700733 printf(" Data key algorithm: %" PRIu64 " %s\n", data_key->algorithm,
734 (data_key->algorithm < kNumAlgorithms ?
735 algo_strings[data_key->algorithm] : "(invalid)"));
736 printf(" Data key version: %" PRIu64 "\n", data_key->key_version);
Bill Richardson60bcbe32010-09-09 14:53:56 -0700737 printf(" Data key sha1sum: ");
738 PrintPubKeySha1Sum(data_key);
739 printf("\n");
Randall Spangler7d6898d2010-06-11 09:22:13 -0700740
741 rsa = PublicKeyToRSA(&key_block->data_key);
742 if (!rsa) {
743 error("Error parsing data key.\n");
vbendebb2b0fcc2010-07-15 15:09:47 -0700744 goto verify_exit;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700745 }
746
747 /* Verify preamble */
vbendebb2b0fcc2010-07-15 15:09:47 -0700748 preamble = bp->preamble;
Randall Spangler87c13d82010-07-19 10:35:40 -0700749 if (0 != VerifyKernelPreamble(
Bill Richardson4f36ef32010-08-09 17:50:14 -0700750 preamble, bp->blob_size - key_block->key_block_size, rsa)) {
Randall Spangler7d6898d2010-06-11 09:22:13 -0700751 error("Error verifying preamble.\n");
vbendebb2b0fcc2010-07-15 15:09:47 -0700752 goto verify_exit;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700753 }
754 now += preamble->preamble_size;
755
756 printf("Preamble:\n");
Bill Richardsona08b5c92010-06-30 21:59:43 -0700757 printf(" Size: 0x%" PRIx64 "\n", preamble->preamble_size);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700758 printf(" Header version: %" PRIu32 ".%" PRIu32"\n",
759 preamble->header_version_major, preamble->header_version_minor);
760 printf(" Kernel version: %" PRIu64 "\n", preamble->kernel_version);
Bill Richardson249677d2010-06-23 11:16:37 -0700761 printf(" Body load address: 0x%" PRIx64 "\n", preamble->body_load_address);
762 printf(" Body size: 0x%" PRIx64 "\n",
Randall Spangler7d6898d2010-06-11 09:22:13 -0700763 preamble->body_signature.data_size);
Randall Spangler87c13d82010-07-19 10:35:40 -0700764 printf(" Bootloader address: 0x%" PRIx64 "\n",
765 preamble->bootloader_address);
Bill Richardson249677d2010-06-23 11:16:37 -0700766 printf(" Bootloader size: 0x%" PRIx64 "\n", preamble->bootloader_size);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700767
768 /* Verify body */
Randall Spangler87c13d82010-07-19 10:35:40 -0700769 if (0 != VerifyData(bp->blob, bp->blob_size, &preamble->body_signature,
770 rsa)) {
Randall Spangler7d6898d2010-06-11 09:22:13 -0700771 error("Error verifying kernel body.\n");
vbendebb2b0fcc2010-07-15 15:09:47 -0700772 goto verify_exit;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700773 }
774 printf("Body verification succeeded.\n");
vbendebb2b0fcc2010-07-15 15:09:47 -0700775
776 rv = 0;
777
778 if (!verbose) {
779 goto verify_exit;
780 }
781
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +0800782 printf("Config:\n%s\n", BpCmdLineLocation(bp, kernel_body_load_address));
vbendebb2b0fcc2010-07-15 15:09:47 -0700783
784verify_exit:
785 FreeBlob(bp);
786 return rv;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700787}
788
789
790int main(int argc, char* argv[]) {
Randall Spangler7d6898d2010-06-11 09:22:13 -0700791 char* filename = NULL;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700792 char* oldfile = NULL;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700793 char* key_block_file = NULL;
794 char* signpubkey = NULL;
795 char* signprivate = NULL;
vbendeb00b90882010-10-21 13:46:16 -0700796 int version = -1;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700797 char* vmlinuz = NULL;
798 char* bootloader = NULL;
799 char* config_file = NULL;
Che-Liang Chiou03762032011-02-22 11:16:51 +0800800 int arch = ARCH_X86;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700801 int vblockonly = 0;
vbendebb2b0fcc2010-07-15 15:09:47 -0700802 int verbose = 0;
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +0800803 uint64_t kernel_body_load_address = CROS_32BIT_ENTRY_ADDR;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700804 uint64_t pad = DEFAULT_PADDING;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700805 int mode = 0;
806 int parse_error = 0;
807 char* e;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700808 int i,r;
809 blob_t *bp;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700810
Bill Richardsona08b5c92010-06-30 21:59:43 -0700811
812 char *progname = strrchr(argv[0], '/');
813 if (progname)
814 progname++;
815 else
816 progname = argv[0];
817
vbendebb2b0fcc2010-07-15 15:09:47 -0700818 while (((i = getopt_long(argc, argv, ":", long_opts, NULL)) != -1) &&
819 !parse_error) {
Randall Spangler7d6898d2010-06-11 09:22:13 -0700820 switch (i) {
vbendebb2b0fcc2010-07-15 15:09:47 -0700821 default:
Randall Spangler7d6898d2010-06-11 09:22:13 -0700822 case '?':
823 /* Unhandled option */
Randall Spangler7d6898d2010-06-11 09:22:13 -0700824 parse_error = 1;
825 break;
826
Bill Richardson4f36ef32010-08-09 17:50:14 -0700827 case 0:
828 /* silently handled option */
829 break;
830
Randall Spangler7d6898d2010-06-11 09:22:13 -0700831 case OPT_MODE_PACK:
Bill Richardsona08b5c92010-06-30 21:59:43 -0700832 case OPT_MODE_REPACK:
Randall Spangler7d6898d2010-06-11 09:22:13 -0700833 case OPT_MODE_VERIFY:
vbendebb2b0fcc2010-07-15 15:09:47 -0700834 if (mode && (mode != i)) {
835 fprintf(stderr, "Only single mode can be specified\n");
836 parse_error = 1;
837 break;
838 }
Randall Spangler7d6898d2010-06-11 09:22:13 -0700839 mode = i;
840 filename = optarg;
841 break;
842
Che-Liang Chiou03762032011-02-22 11:16:51 +0800843 case OPT_ARCH:
844 if (!strcasecmp(optarg, "x86"))
845 arch = ARCH_X86;
846 else if (!strcasecmp(optarg, "arm"))
847 arch = ARCH_ARM;
848 else {
849 fprintf(stderr, "Unknown architecture string: %s\n", optarg);
850 parse_error = 1;
851 }
852 break;
853
Bill Richardsona08b5c92010-06-30 21:59:43 -0700854 case OPT_OLDBLOB:
855 oldfile = optarg;
856 break;
857
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +0800858 case OPT_KLOADADDR:
859 kernel_body_load_address = strtoul(optarg, &e, 0);
860 if (!*optarg || (e && *e)) {
861 fprintf(stderr, "Invalid --kloadaddr\n");
862 parse_error = 1;
863 }
864 break;
865
Randall Spangler7d6898d2010-06-11 09:22:13 -0700866 case OPT_KEYBLOCK:
867 key_block_file = optarg;
868 break;
869
870 case OPT_SIGNPUBKEY:
871 signpubkey = optarg;
872 break;
873
874 case OPT_SIGNPRIVATE:
875 signprivate = optarg;
876 break;
877
878 case OPT_VMLINUZ:
879 vmlinuz = optarg;
880 break;
881
882 case OPT_BOOTLOADER:
883 bootloader = optarg;
884 break;
885
886 case OPT_CONFIG:
887 config_file = optarg;
888 break;
889
Bill Richardsona08b5c92010-06-30 21:59:43 -0700890 case OPT_VBLOCKONLY:
891 vblockonly = 1;
892 break;
893
Randall Spangler7d6898d2010-06-11 09:22:13 -0700894 case OPT_VERSION:
895 version = strtoul(optarg, &e, 0);
896 if (!*optarg || (e && *e)) {
Bill Richardsona08b5c92010-06-30 21:59:43 -0700897 fprintf(stderr, "Invalid --version\n");
Randall Spangler7d6898d2010-06-11 09:22:13 -0700898 parse_error = 1;
899 }
900 break;
901
902 case OPT_PAD:
903 pad = strtoul(optarg, &e, 0);
904 if (!*optarg || (e && *e)) {
Bill Richardsona08b5c92010-06-30 21:59:43 -0700905 fprintf(stderr, "Invalid --pad\n");
Randall Spangler7d6898d2010-06-11 09:22:13 -0700906 parse_error = 1;
907 }
908 break;
vbendebb2b0fcc2010-07-15 15:09:47 -0700909
910 case OPT_VERBOSE:
911 verbose = 1;
912 break;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700913 }
914 }
915
916 if (parse_error)
Bill Richardsona08b5c92010-06-30 21:59:43 -0700917 return PrintHelp(progname);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700918
919 switch(mode) {
920 case OPT_MODE_PACK:
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +0800921 bp = NewBlob(version, vmlinuz, bootloader, config_file, arch,
922 kernel_body_load_address);
Bill Richardsona08b5c92010-06-30 21:59:43 -0700923 if (!bp)
924 return 1;
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +0800925 r = Pack(filename, key_block_file, signprivate, bp, pad, vblockonly,
926 kernel_body_load_address);
Bill Richardsona08b5c92010-06-30 21:59:43 -0700927 FreeBlob(bp);
928 return r;
929
930 case OPT_MODE_REPACK:
vbendeb00b90882010-10-21 13:46:16 -0700931 if (!config_file && !key_block_file && (version<0)) {
vbendebb2b0fcc2010-07-15 15:09:47 -0700932 fprintf(stderr,
vbendeb858fffb2010-10-06 09:51:44 -0700933 "You must supply at least one of "
934 "--config, --keyblock or --version\n");
vbendebb2b0fcc2010-07-15 15:09:47 -0700935 return 1;
936 }
937
Bill Richardsona08b5c92010-06-30 21:59:43 -0700938 bp = OldBlob(oldfile);
939 if (!bp)
940 return 1;
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +0800941 r = ReplaceConfig(bp, config_file, kernel_body_load_address);
vbendebb2b0fcc2010-07-15 15:09:47 -0700942 if (!r) {
vbendeb00b90882010-10-21 13:46:16 -0700943 if (version >= 0) {
Che-Liang Chiou03762032011-02-22 11:16:51 +0800944 bp->kernel_version = (uint64_t) version;
vbendeb858fffb2010-10-06 09:51:44 -0700945 }
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +0800946 r = Pack(filename, key_block_file, signprivate, bp, pad, vblockonly,
947 kernel_body_load_address);
vbendebb2b0fcc2010-07-15 15:09:47 -0700948 }
Bill Richardsona08b5c92010-06-30 21:59:43 -0700949 FreeBlob(bp);
950 return r;
951
Randall Spangler7d6898d2010-06-11 09:22:13 -0700952 case OPT_MODE_VERIFY:
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +0800953 return Verify(filename, signpubkey, verbose, key_block_file,
954 kernel_body_load_address);
Bill Richardsona08b5c92010-06-30 21:59:43 -0700955
Randall Spangler7d6898d2010-06-11 09:22:13 -0700956 default:
Bill Richardsona08b5c92010-06-30 21:59:43 -0700957 fprintf(stderr,
958 "You must specify a mode: --pack, --repack or --verify\n");
959 return PrintHelp(progname);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700960 }
961}