blob: 29d508a0f51b82cb46113b673c644167d3078065 [file] [log] [blame]
Bill Richardson72e344d2012-03-19 12:47:18 -07001/* Copyright (c) 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>
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
Bill Richardson72e344d2012-03-19 12:47:18 -070025/* Global opts */
Bill Richardson249677d2010-06-23 11:16:37 -070026static int opt_debug = 0;
Bill Richardson72e344d2012-03-19 12:47:18 -070027static int opt_verbose = 0;
28static int opt_vblockonly = 0;
29static uint64_t opt_pad = 65536;
Bill Richardson249677d2010-06-23 11:16:37 -070030
31
Randall Spangler7d6898d2010-06-11 09:22:13 -070032/* Command line options */
33enum {
34 OPT_MODE_PACK = 1000,
Bill Richardsona08b5c92010-06-30 21:59:43 -070035 OPT_MODE_REPACK,
Randall Spangler7d6898d2010-06-11 09:22:13 -070036 OPT_MODE_VERIFY,
Che-Liang Chiou03762032011-02-22 11:16:51 +080037 OPT_ARCH,
Bill Richardsona08b5c92010-06-30 21:59:43 -070038 OPT_OLDBLOB,
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +080039 OPT_KLOADADDR,
Randall Spangler7d6898d2010-06-11 09:22:13 -070040 OPT_KEYBLOCK,
41 OPT_SIGNPUBKEY,
42 OPT_SIGNPRIVATE,
43 OPT_VERSION,
44 OPT_VMLINUZ,
45 OPT_BOOTLOADER,
46 OPT_CONFIG,
Bill Richardsona08b5c92010-06-30 21:59:43 -070047 OPT_VBLOCKONLY,
Randall Spangler7d6898d2010-06-11 09:22:13 -070048 OPT_PAD,
vbendebb2b0fcc2010-07-15 15:09:47 -070049 OPT_VERBOSE,
Randall Spanglerae87b922011-05-12 13:27:28 -070050 OPT_MINVERSION,
Randall Spangler7d6898d2010-06-11 09:22:13 -070051};
52
Bill Richardson72e344d2012-03-19 12:47:18 -070053typedef enum {
Che-Liang Chiou03762032011-02-22 11:16:51 +080054 ARCH_ARM,
55 ARCH_X86 /* default */
Bill Richardson72e344d2012-03-19 12:47:18 -070056} arch_t;
Che-Liang Chiou03762032011-02-22 11:16:51 +080057
Randall Spangler7d6898d2010-06-11 09:22:13 -070058static struct option long_opts[] = {
59 {"pack", 1, 0, OPT_MODE_PACK },
Bill Richardsona08b5c92010-06-30 21:59:43 -070060 {"repack", 1, 0, OPT_MODE_REPACK },
Randall Spangler7d6898d2010-06-11 09:22:13 -070061 {"verify", 1, 0, OPT_MODE_VERIFY },
Che-Liang Chiou03762032011-02-22 11:16:51 +080062 {"arch", 1, 0, OPT_ARCH },
Bill Richardsona08b5c92010-06-30 21:59:43 -070063 {"oldblob", 1, 0, OPT_OLDBLOB },
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +080064 {"kloadaddr", 1, 0, OPT_KLOADADDR },
Randall Spangler7d6898d2010-06-11 09:22:13 -070065 {"keyblock", 1, 0, OPT_KEYBLOCK },
66 {"signpubkey", 1, 0, OPT_SIGNPUBKEY },
67 {"signprivate", 1, 0, OPT_SIGNPRIVATE },
68 {"version", 1, 0, OPT_VERSION },
Randall Spanglerae87b922011-05-12 13:27:28 -070069 {"minversion", 1, 0, OPT_MINVERSION },
Randall Spangler7d6898d2010-06-11 09:22:13 -070070 {"vmlinuz", 1, 0, OPT_VMLINUZ },
71 {"bootloader", 1, 0, OPT_BOOTLOADER },
72 {"config", 1, 0, OPT_CONFIG },
Bill Richardsona08b5c92010-06-30 21:59:43 -070073 {"vblockonly", 0, 0, OPT_VBLOCKONLY },
Randall Spangler7d6898d2010-06-11 09:22:13 -070074 {"pad", 1, 0, OPT_PAD },
Bill Richardson72e344d2012-03-19 12:47:18 -070075 {"verbose", 0, &opt_verbose, 1 },
Bill Richardson249677d2010-06-23 11:16:37 -070076 {"debug", 0, &opt_debug, 1 },
Randall Spangler7d6898d2010-06-11 09:22:13 -070077 {NULL, 0, 0, 0}
78};
79
80
81/* Print help and return error */
Bill Richardsona08b5c92010-06-30 21:59:43 -070082static int PrintHelp(char *progname) {
83 fprintf(stderr,
84 "This program creates, signs, and verifies the kernel blob\n");
85 fprintf(stderr,
86 "\n"
87 "Usage: %s --pack <file> [PARAMETERS]\n"
88 "\n"
89 " Required parameters:\n"
90 " --keyblock <file> Key block in .keyblock format\n"
Bill Richardson72e344d2012-03-19 12:47:18 -070091 " --signprivate <file> Private key to sign kernel data,\n"
92 " in .vbprivk format\n"
Bill Richardsona08b5c92010-06-30 21:59:43 -070093 " --version <number> Kernel version\n"
94 " --vmlinuz <file> Linux kernel bzImage file\n"
95 " --bootloader <file> Bootloader stub\n"
vbendebb2b0fcc2010-07-15 15:09:47 -070096 " --config <file> Command line file\n"
Che-Liang Chiou03762032011-02-22 11:16:51 +080097 " --arch <arch> Cpu architecture (default x86)\n"
Bill Richardsona08b5c92010-06-30 21:59:43 -070098 "\n"
99 " Optional:\n"
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +0800100 " --kloadaddr <address> Assign kernel body load address\n"
Bill Richardsona08b5c92010-06-30 21:59:43 -0700101 " --pad <number> Verification padding size in bytes\n"
102 " --vblockonly Emit just the verification blob\n",
103 progname);
104 fprintf(stderr,
105 "\nOR\n\n"
106 "Usage: %s --repack <file> [PARAMETERS]\n"
107 "\n"
Bill Richardson72e344d2012-03-19 12:47:18 -0700108 " Required parameters:\n"
109 " --signprivate <file> Private key to sign kernel data,\n"
110 " in .vbprivk format\n"
Bill Richardsona08b5c92010-06-30 21:59:43 -0700111 " --oldblob <file> Previously packed kernel blob\n"
Bill Richardson72e344d2012-03-19 12:47:18 -0700112 " (including verfication blob)\n"
Bill Richardsona08b5c92010-06-30 21:59:43 -0700113 "\n"
114 " Optional:\n"
Bill Richardson72e344d2012-03-19 12:47:18 -0700115 " --keyblock <file> Key block in .keyblock format\n"
116 " --config <file> New command line file\n"
117 " --version <number> Kernel version\n"
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +0800118 " --kloadaddr <address> Assign kernel body load address\n"
Bill Richardson72e344d2012-03-19 12:47:18 -0700119 " --pad <number> Verification blob size in bytes\n"
Bill Richardsona08b5c92010-06-30 21:59:43 -0700120 " --vblockonly Emit just the verification blob\n",
121 progname);
122 fprintf(stderr,
123 "\nOR\n\n"
124 "Usage: %s --verify <file> [PARAMETERS]\n"
125 "\n"
vbendebb2b0fcc2010-07-15 15:09:47 -0700126 " Optional:\n"
Bill Richardson4f36ef32010-08-09 17:50:14 -0700127 " --signpubkey <file>"
Bill Richardson72e344d2012-03-19 12:47:18 -0700128 " Public key to verify kernel keyblock,\n"
129 " in .vbpubk format\n"
vbendebb2b0fcc2010-07-15 15:09:47 -0700130 " --verbose Print a more detailed report\n"
Bill Richardson72e344d2012-03-19 12:47:18 -0700131 " --keyblock <file> Outputs the verified key block,\n"
132 " in .keyblock format\n"
Randall Spangler7ecb39d2011-05-12 15:37:45 -0700133 " --pad <number> Verification padding size in bytes\n"
Randall Spanglerae87b922011-05-12 13:27:28 -0700134 " --minversion <number> Minimum combined kernel key version\n"
135 " and kernel version\n"
Bill Richardsona08b5c92010-06-30 21:59:43 -0700136 "\n",
137 progname);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700138 return 1;
139}
140
Bill Richardson249677d2010-06-23 11:16:37 -0700141static void Debug(const char *format, ...) {
142 if (!opt_debug)
143 return;
144
145 va_list ap;
146 va_start(ap, format);
147 fprintf(stderr, "DEBUG: ");
148 vfprintf(stderr, format, ap);
149 va_end(ap);
150}
151
Bill Richardson72e344d2012-03-19 12:47:18 -0700152static void Fatal(const char *format, ...) {
153 va_list ap;
154 va_start(ap, format);
155 fprintf(stderr, "ERROR: ");
156 vfprintf(stderr, format, ap);
157 va_end(ap);
158 exit(1);
159}
160
Bill Richardson2f6a71f2010-10-14 09:25:39 -0700161/* Return an explanation when fread() fails. */
162static const char *error_fread(FILE *fp) {
163 const char *retval = "beats me why";
164 if (feof(fp))
165 retval = "EOF";
166 else if (ferror(fp))
167 retval = strerror(errno);
168 clearerr(fp);
169 return retval;
170}
Randall Spangler7d6898d2010-06-11 09:22:13 -0700171
172/* Return the smallest integral multiple of [alignment] that is equal
173 * to or greater than [val]. Used to determine the number of
174 * pages/sectors/blocks/whatever needed to contain [val]
175 * items/bytes/etc. */
176static uint64_t roundup(uint64_t val, uint64_t alignment) {
177 uint64_t rem = val % alignment;
178 if ( rem )
179 return val + (alignment - rem);
180 return val;
181}
182
183
184/* Match regexp /\b--\b/ to delimit the start of the kernel commandline. If we
185 * don't find one, we'll use the whole thing. */
186static unsigned int find_cmdline_start(char *input, unsigned int max_len) {
187 int start = 0;
188 int i;
189 for(i = 0; i < max_len - 1 && input[i]; i++) {
190 if ('-' == input[i] && '-' == input[i + 1]) { /* found a "--" */
191 if ((i == 0 || ' ' == input[i - 1]) && /* nothing before it */
192 (i + 2 >= max_len || ' ' == input[i+2])) { /* nothing after it */
193 start = i+2; /* note: hope there's a trailing '\0' */
194 break;
195 }
196 }
197 }
198 while(' ' == input[start]) /* skip leading spaces */
199 start++;
200
201 return start;
202}
203
204
Bill Richardson72e344d2012-03-19 12:47:18 -0700205/****************************************************************************/
206/* Here are globals containing all the bits & pieces I'm working on. */
207
208/* The individual parts that go into the kernel blob */
209uint8_t *g_kernel_data;
210uint64_t g_kernel_size;
211uint8_t *g_param_data;
212uint64_t g_param_size;
213uint8_t *g_config_data;
214uint64_t g_config_size;
215uint8_t *g_bootloader_data;
216uint64_t g_bootloader_size;
217uint64_t g_bootloader_address;
Bill Richardsonc8b9ca62012-03-14 10:54:05 -0700218
219
Bill Richardson72e344d2012-03-19 12:47:18 -0700220/* The individual parts of the verification blob (including the data that
221 * immediately follows the headers) */
222VbKeyBlockHeader* g_keyblock;
223VbKernelPreambleHeader* g_preamble;
vbendebb2b0fcc2010-07-15 15:09:47 -0700224
Bill Richardson72e344d2012-03-19 12:47:18 -0700225/****************************************************************************/
Bill Richardsona08b5c92010-06-30 21:59:43 -0700226
vbendebb2b0fcc2010-07-15 15:09:47 -0700227/*
228 * Read the kernel command line from a file. Get rid of \n characters along
229 * the way and verify that the line fits into a 4K buffer.
230 *
231 * Return the buffer contaning the line on success (and set the line length
232 * using the passed in parameter), or NULL in case something goes wrong.
233 */
234static uint8_t* ReadConfigFile(const char* config_file, uint64_t* config_size)
235{
236 uint8_t* config_buf;
237 int ii;
238
239 config_buf = ReadFile(config_file, config_size);
240 Debug(" config file size=0x%" PRIx64 "\n", *config_size);
241 if (CROS_CONFIG_SIZE <= *config_size) { /* need room for trailing '\0' */
Randall Spangler32a65262011-06-27 10:49:11 -0700242 VbExError("Config file %s is too large (>= %d bytes)\n",
243 config_file, CROS_CONFIG_SIZE);
vbendebb2b0fcc2010-07-15 15:09:47 -0700244 return NULL;
245 }
246
247 /* Replace newlines with spaces */
248 for (ii = 0; ii < *config_size; ii++) {
249 if ('\n' == config_buf[ii]) {
250 config_buf[ii] = ' ';
251 }
252 }
253 return config_buf;
254}
255
Bill Richardson72e344d2012-03-19 12:47:18 -0700256
257/* Offset of kernel command line string from start of packed kernel blob */
258static uint64_t CmdLineOffset(VbKernelPreambleHeader *preamble) {
259 return preamble->bootloader_address - preamble->body_load_address -
260 CROS_CONFIG_SIZE - CROS_PARAMS_SIZE;
261}
262
263/* This initializes g_vmlinuz and g_param from a standard vmlinuz file.
264 * It returns 0 on error. */
265static int ImportVmlinuzFile(const char *vmlinuz_file, arch_t arch,
266 uint64_t kernel_body_load_address) {
267 uint8_t *kernel_buf;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700268 uint64_t kernel_size;
269 uint64_t kernel32_start = 0;
270 uint64_t kernel32_size = 0;
Bill Richardson72e344d2012-03-19 12:47:18 -0700271 struct linux_kernel_header* lh = 0;
272 struct linux_kernel_params* params = 0;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700273
274 /* Read the kernel */
Bill Richardson72e344d2012-03-19 12:47:18 -0700275 Debug("Reading %s\n", vmlinuz_file);
276 kernel_buf = ReadFile(vmlinuz_file, &kernel_size);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700277 if (!kernel_buf)
Bill Richardsona08b5c92010-06-30 21:59:43 -0700278 return 0;
Bill Richardson249677d2010-06-23 11:16:37 -0700279 Debug(" kernel file size=0x%" PRIx64 "\n", kernel_size);
Bill Richardson72e344d2012-03-19 12:47:18 -0700280 if (!kernel_size)
281 Fatal("Empty kernel file\n");
282
283 /* Go ahead and allocate the param region anyway. I don't think we need it
284 * for non-x86, but let's keep it for now. */
285 g_param_size = CROS_PARAMS_SIZE;
286 g_param_data= VbExMalloc(g_param_size);
287 Memset(g_param_data, 0, g_param_size);
288
289 /* Unless we're handling x86, the kernel is the kernel, so we're done. */
290 if (arch != ARCH_X86) {
291 g_kernel_data = kernel_buf;
292 g_kernel_size = kernel_size;
293 return 1;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700294 }
295
Bill Richardson72e344d2012-03-19 12:47:18 -0700296 /* The first part of the x86 vmlinuz is a header, followed by a real-mode
297 * boot stub. We only want the 32-bit part. */
298 lh = (struct linux_kernel_header *)kernel_buf;
299 kernel32_start = (lh->setup_sects + 1) << 9;
300 if (kernel32_start >= kernel_size)
301 Fatal("Malformed kernel\n");
Randall Spangler7d6898d2010-06-11 09:22:13 -0700302 kernel32_size = kernel_size - kernel32_start;
Bill Richardson72e344d2012-03-19 12:47:18 -0700303
Bill Richardson249677d2010-06-23 11:16:37 -0700304 Debug(" kernel32_start=0x%" PRIx64 "\n", kernel32_start);
305 Debug(" kernel32_size=0x%" PRIx64 "\n", kernel32_size);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700306
Bill Richardson72e344d2012-03-19 12:47:18 -0700307 /* Keep just the 32-bit kernel. */
308 if (kernel32_size) {
309 g_kernel_size = kernel32_size;
310 g_kernel_data = VbExMalloc(g_kernel_size);
311 Memcpy(g_kernel_data, kernel_buf + kernel32_start, kernel32_size);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700312 }
Randall Spangler7d6898d2010-06-11 09:22:13 -0700313
Bill Richardson72e344d2012-03-19 12:47:18 -0700314 /* Copy the original zeropage data from kernel_buf into g_param_data, then
315 * tweak a few fields for our purposes */
316 params = (struct linux_kernel_params *)(g_param_data);
317 Memcpy(&(params->setup_sects), &(lh->setup_sects),
318 sizeof(*lh) - offsetof(struct linux_kernel_header, setup_sects));
Randall Spangler7d6898d2010-06-11 09:22:13 -0700319 params->boot_flag = 0;
Bill Richardson72e344d2012-03-19 12:47:18 -0700320 params->ramdisk_image = 0; /* we don't support initrd */
Randall Spangler7d6898d2010-06-11 09:22:13 -0700321 params->ramdisk_size = 0;
322 params->type_of_loader = 0xff;
Bill Richardson72e344d2012-03-19 12:47:18 -0700323 /* We need to point to the kernel commandline arg. On disk, it will come
324 * right after the 32-bit part of the kernel. */
325 params->cmd_line_ptr = kernel_body_load_address +
326 roundup(kernel32_size, CROS_ALIGN) +
327 find_cmdline_start((char *)g_config_data, g_config_size);
328 Debug(" cmdline_addr=0x%x\n", params->cmd_line_ptr);
Che-Liang Chiou475bf442010-08-23 11:20:44 +0800329 /* A fake e820 memory map with 2 entries */
330 params->n_e820_entry = 2;
331 params->e820_entries[0].start_addr = 0x00000000;
332 params->e820_entries[0].segment_size = 0x00001000;
333 params->e820_entries[0].segment_type = E820_TYPE_RAM;
334 params->e820_entries[1].start_addr = 0xfffff000;
335 params->e820_entries[1].segment_size = 0x00001000;
336 params->e820_entries[1].segment_type = E820_TYPE_RESERVED;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700337
Bill Richardson72e344d2012-03-19 12:47:18 -0700338 /* done */
Randall Spangler32a65262011-06-27 10:49:11 -0700339 free(kernel_buf);
Bill Richardson72e344d2012-03-19 12:47:18 -0700340 return 1;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700341}
342
Bill Richardson72e344d2012-03-19 12:47:18 -0700343/* This returns just the kernel blob, with the verification blob separated
344 * and copied to new memory in g_keyblock and g_preamble. */
345static uint8_t* ReadOldBlobFromFileOrDie(const char *filename,
346 uint64_t* size_ptr) {
vbendebb2b0fcc2010-07-15 15:09:47 -0700347 FILE* fp = NULL;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700348 struct stat statbuf;
349 VbKeyBlockHeader* key_block;
350 VbKernelPreambleHeader* preamble;
351 uint64_t now = 0;
Bill Richardson72e344d2012-03-19 12:47:18 -0700352 uint8_t* buf;
353 uint8_t* kernel_blob_data;
354 uint64_t kernel_blob_size;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700355
Bill Richardson72e344d2012-03-19 12:47:18 -0700356 if (0 != stat(filename, &statbuf))
357 Fatal("Unable to stat %s: %s\n", filename, strerror(errno));
Bill Richardsona08b5c92010-06-30 21:59:43 -0700358
359 Debug("%s size is 0x%" PRIx64 "\n", filename, statbuf.st_size);
Bill Richardson72e344d2012-03-19 12:47:18 -0700360 if (statbuf.st_size < opt_pad)
361 Fatal("%s is too small to be a valid kernel blob\n");
Bill Richardsona08b5c92010-06-30 21:59:43 -0700362
363 Debug("Reading %s\n", filename);
364 fp = fopen(filename, "rb");
Bill Richardson72e344d2012-03-19 12:47:18 -0700365 if (!fp)
366 Fatal("Unable to open file %s: %s\n", filename, strerror(errno));
Bill Richardsona08b5c92010-06-30 21:59:43 -0700367
Bill Richardson72e344d2012-03-19 12:47:18 -0700368 buf = VbExMalloc(opt_pad);
369 if (1 != fread(buf, opt_pad, 1, fp))
370 Fatal("Unable to read header from %s: %s\n", filename, error_fread(fp));
vbendebb2b0fcc2010-07-15 15:09:47 -0700371
Bill Richardson72e344d2012-03-19 12:47:18 -0700372 /* Sanity-check the key_block */
Bill Richardsona08b5c92010-06-30 21:59:43 -0700373 key_block = (VbKeyBlockHeader*)buf;
374 Debug("Keyblock is 0x%" PRIx64 " bytes\n", key_block->key_block_size);
375 now += key_block->key_block_size;
Bill Richardson72e344d2012-03-19 12:47:18 -0700376 if (now > statbuf.st_size)
377 Fatal("key_block_size advances past the end of the blob\n");
378 if (now > opt_pad)
379 Fatal("key_block_size advances past %" PRIu64 " byte padding\n",
380 opt_pad);
381 /* LGTM */
382 g_keyblock = (VbKeyBlockHeader*)VbExMalloc(key_block->key_block_size);
383 Memcpy(g_keyblock, key_block, key_block->key_block_size);
Bill Richardsona08b5c92010-06-30 21:59:43 -0700384
Bill Richardson72e344d2012-03-19 12:47:18 -0700385 /* And the preamble */
Bill Richardsona08b5c92010-06-30 21:59:43 -0700386 preamble = (VbKernelPreambleHeader*)(buf + now);
387 Debug("Preamble is 0x%" PRIx64 " bytes\n", preamble->preamble_size);
388 now += preamble->preamble_size;
Bill Richardson72e344d2012-03-19 12:47:18 -0700389 if (now > statbuf.st_size)
390 Fatal("preamble_size advances past the end of the blob\n");
391 if (now > opt_pad)
392 Fatal("preamble_size advances past %" PRIu64 " byte padding\n",
393 opt_pad);
394 /* LGTM */
395 Debug(" kernel_version = %d\n", preamble->kernel_version);
396 Debug(" bootloader_address = 0x%" PRIx64 "\n", preamble->bootloader_address);
397 Debug(" bootloader_size = 0x%" PRIx64 "\n", preamble->bootloader_size);
398 Debug(" kern_blob_size = 0x%" PRIx64 "\n",
399 preamble->body_signature.data_size);
400 g_preamble = (VbKernelPreambleHeader*)VbExMalloc(preamble->preamble_size);
401 Memcpy(g_preamble, preamble, preamble->preamble_size);
Bill Richardsona08b5c92010-06-30 21:59:43 -0700402
Bill Richardson72e344d2012-03-19 12:47:18 -0700403 /* Now for the kernel blob */
Bill Richardsona08b5c92010-06-30 21:59:43 -0700404 Debug("kernel blob is at offset 0x%" PRIx64 "\n", now);
Bill Richardson72e344d2012-03-19 12:47:18 -0700405 if (0 != fseek(fp, now, SEEK_SET))
406 Fatal("Unable to seek to 0x%" PRIx64 " in %s: %s\n", now, filename,
Bill Richardsona08b5c92010-06-30 21:59:43 -0700407 strerror(errno));
Bill Richardsona08b5c92010-06-30 21:59:43 -0700408
Bill Richardson72e344d2012-03-19 12:47:18 -0700409 /* Sanity check */
410 kernel_blob_size = statbuf.st_size - now;
411 if (!kernel_blob_size)
412 Fatal("No kernel blob found\n");
413 if (kernel_blob_size < preamble->body_signature.data_size)
414 fprintf(stderr, "Warning: kernel file only has 0x%" PRIx64 " bytes\n",
415 kernel_blob_size);
416 kernel_blob_data = VbExMalloc(kernel_blob_size);
Bill Richardsona08b5c92010-06-30 21:59:43 -0700417
Bill Richardson72e344d2012-03-19 12:47:18 -0700418 /* Read it in */
419 if (1 != fread(kernel_blob_data, kernel_blob_size, 1, fp))
420 Fatal("Unable to read kernel blob from %s: %s\n", filename,
Randall Spangler32a65262011-06-27 10:49:11 -0700421 error_fread(fp));
Bill Richardsona08b5c92010-06-30 21:59:43 -0700422
Bill Richardson72e344d2012-03-19 12:47:18 -0700423 /* Done */
424 VbExFree(buf);
Bill Richardsona08b5c92010-06-30 21:59:43 -0700425
Bill Richardson72e344d2012-03-19 12:47:18 -0700426 if (size_ptr)
427 *size_ptr = kernel_blob_size;
428
429 return kernel_blob_data;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700430}
431
432
Bill Richardson72e344d2012-03-19 12:47:18 -0700433/* Split a kernel blob into separate g_kernel, g_param, g_config, and
434 * g_bootloader parts. */
435static void UnpackKernelBlob(uint8_t *kernel_blob_data,
436 uint64_t kernel_blob_size) {
437
438 uint64_t k_blob_size = g_preamble->body_signature.data_size;
439 uint64_t k_blob_ofs = 0;
440 uint64_t b_size = g_preamble->bootloader_size;
441 uint64_t b_ofs = k_blob_ofs + g_preamble->bootloader_address -
442 g_preamble->body_load_address;
443 uint64_t p_ofs = b_ofs - CROS_CONFIG_SIZE;
444 uint64_t c_ofs = p_ofs - CROS_PARAMS_SIZE;
Bill Richardson72e344d2012-03-19 12:47:18 -0700445
446 Debug("k_blob_size = 0x%" PRIx64 "\n", k_blob_size );
447 Debug("k_blob_ofs = 0x%" PRIx64 "\n", k_blob_ofs );
448 Debug("b_size = 0x%" PRIx64 "\n", b_size );
449 Debug("b_ofs = 0x%" PRIx64 "\n", b_ofs );
450 Debug("p_ofs = 0x%" PRIx64 "\n", p_ofs );
451 Debug("c_ofs = 0x%" PRIx64 "\n", c_ofs );
452
453 g_kernel_size = c_ofs;
454 g_kernel_data = VbExMalloc(g_kernel_size);
455 Memcpy(g_kernel_data, kernel_blob_data, g_kernel_size);
456
457 g_param_size = CROS_PARAMS_SIZE;
458 g_param_data = VbExMalloc(g_param_size);
459 Memcpy(g_param_data, kernel_blob_data + p_ofs, g_param_size);
460
461 g_config_size = CROS_CONFIG_SIZE;
462 g_config_data = VbExMalloc(g_config_size);
463 Memcpy(g_config_data, kernel_blob_data + c_ofs, g_config_size);
464
465 g_bootloader_size = b_size;
466 g_bootloader_data = VbExMalloc(g_bootloader_size);
467 Memcpy(g_bootloader_data, kernel_blob_data + b_ofs, g_bootloader_size);
468}
469
470
471
472/****************************************************************************/
473
474static uint8_t* CreateKernelBlob(uint64_t kernel_body_load_address,
475 arch_t arch,
476 uint64_t *size_ptr) {
477 uint8_t *kern_blob;
478 uint64_t kern_blob_size;
479 uint64_t now;
480 uint64_t bootloader_size = roundup(g_bootloader_size, CROS_ALIGN);
481
482 /* Put the kernel blob together */
483 kern_blob_size = roundup(g_kernel_size, CROS_ALIGN) +
484 CROS_CONFIG_SIZE + CROS_PARAMS_SIZE + bootloader_size;
485 Debug("kern_blob_size=0x%" PRIx64 "\n", kern_blob_size);
486 kern_blob = VbExMalloc(kern_blob_size);
487 Memset(kern_blob, 0, kern_blob_size);
488 now = 0;
489
490 Debug("kernel goes at kern_blob+0x%" PRIx64 "\n", now);
491
492 Memcpy(kern_blob+now, g_kernel_data, g_kernel_size);
493 now += roundup(g_kernel_size, CROS_ALIGN);
494
495 Debug("config goes at kern_blob+0x%" PRIx64 "\n", now);
496 if (g_config_size)
497 Memcpy(kern_blob + now, g_config_data, g_config_size);
498 now += CROS_CONFIG_SIZE;
499
500 Debug("params goes at kern_blob+0x%" PRIx64 "\n", now);
501 if (g_param_size) {
502 Memcpy(kern_blob + now, g_param_data, g_param_size);
503 }
504 now += CROS_PARAMS_SIZE;
505
506 Debug("bootloader goes at kern_blob+0x%" PRIx64 "\n", now);
507 g_bootloader_address = kernel_body_load_address + now;
508 Debug(" bootloader_address=0x%" PRIx64 "\n", g_bootloader_address);
509 Debug(" bootloader_size=0x%" PRIx64 "\n", bootloader_size);
510 if (bootloader_size)
511 Memcpy(kern_blob + now, g_bootloader_data, g_bootloader_size);
512 now += bootloader_size;
513 Debug("end of kern_blob at kern_blob+0x%" PRIx64 "\n", now);
514
515 /* Done */
516 if (size_ptr)
517 *size_ptr = kern_blob_size;
518
519 return kern_blob;
520}
521
522static int Pack(const char* outfile,
523 uint8_t *kernel_blob,
524 uint64_t kernel_size,
525 int version,
526 uint64_t kernel_body_load_address,
527 VbPrivateKey* signpriv_key) {
Bill Richardsona08b5c92010-06-30 21:59:43 -0700528 VbSignature* body_sig;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700529 FILE* f;
530 uint64_t i;
Bill Richardsonc8b9ca62012-03-14 10:54:05 -0700531 uint64_t written = 0;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700532
Randall Spangler7d6898d2010-06-11 09:22:13 -0700533 /* Sign the kernel data */
Bill Richardson72e344d2012-03-19 12:47:18 -0700534 body_sig = CalculateSignature(kernel_blob, kernel_size, signpriv_key);
535 if (!body_sig)
536 Fatal("Error calculating body signature\n");
Randall Spangler7d6898d2010-06-11 09:22:13 -0700537
538 /* Create preamble */
Bill Richardson72e344d2012-03-19 12:47:18 -0700539 g_preamble = CreateKernelPreamble(version,
540 kernel_body_load_address,
541 g_bootloader_address,
542 roundup(g_bootloader_size, CROS_ALIGN),
543 body_sig,
544 opt_pad - g_keyblock->key_block_size,
545 signpriv_key);
546 if (!g_preamble) {
Randall Spangler32a65262011-06-27 10:49:11 -0700547 VbExError("Error creating preamble.\n");
Randall Spangler7d6898d2010-06-11 09:22:13 -0700548 return 1;
549 }
Randall Spangler7d6898d2010-06-11 09:22:13 -0700550 /* Write the output file */
Bill Richardson249677d2010-06-23 11:16:37 -0700551 Debug("writing %s...\n", outfile);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700552 f = fopen(outfile, "wb");
553 if (!f) {
Randall Spangler32a65262011-06-27 10:49:11 -0700554 VbExError("Can't open output file %s\n", outfile);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700555 return 1;
556 }
Bill Richardson72e344d2012-03-19 12:47:18 -0700557 Debug("0x%" PRIx64 " bytes of key_block\n", g_keyblock->key_block_size);
558 Debug("0x%" PRIx64 " bytes of preamble\n", g_preamble->preamble_size);
559 i = ((1 != fwrite(g_keyblock, g_keyblock->key_block_size, 1, f)) ||
560 (1 != fwrite(g_preamble, g_preamble->preamble_size, 1, f)));
Randall Spangler7d6898d2010-06-11 09:22:13 -0700561 if (i) {
Randall Spangler32a65262011-06-27 10:49:11 -0700562 VbExError("Can't write output file %s\n", outfile);
Bill Richardsona08b5c92010-06-30 21:59:43 -0700563 fclose(f);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700564 unlink(outfile);
565 return 1;
566 }
Bill Richardson72e344d2012-03-19 12:47:18 -0700567 written += g_keyblock->key_block_size;
568 written += g_preamble->preamble_size;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700569
Bill Richardson72e344d2012-03-19 12:47:18 -0700570 if (!opt_vblockonly) {
571 Debug("0x%" PRIx64 " bytes of kern_blob\n", kernel_size);
572 i = (1 != fwrite(kernel_blob, kernel_size, 1, f));
Bill Richardsona08b5c92010-06-30 21:59:43 -0700573 if (i) {
Bill Richardsona08b5c92010-06-30 21:59:43 -0700574 fclose(f);
575 unlink(outfile);
Bill Richardson72e344d2012-03-19 12:47:18 -0700576 Fatal("Can't write output file %s\n", outfile);
Bill Richardsona08b5c92010-06-30 21:59:43 -0700577 }
Bill Richardson72e344d2012-03-19 12:47:18 -0700578 written += kernel_size;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700579 }
Bill Richardsonc8b9ca62012-03-14 10:54:05 -0700580 Debug("0x%" PRIx64 " bytes total\n", written);
Bill Richardsona08b5c92010-06-30 21:59:43 -0700581 fclose(f);
582
Randall Spangler7d6898d2010-06-11 09:22:13 -0700583 /* Success */
584 return 0;
585}
586
Bill Richardson72e344d2012-03-19 12:47:18 -0700587static int Verify(uint8_t* kernel_blob,
588 uint64_t kernel_size,
589 VbPublicKey* signpub_key,
590 const char* keyblock_outfile,
591 uint64_t min_version) {
Randall Spangler7d6898d2010-06-11 09:22:13 -0700592 VbPublicKey* data_key;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700593 RSAPublicKey* rsa;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700594
Bill Richardson72e344d2012-03-19 12:47:18 -0700595 if (0 != KeyBlockVerify(g_keyblock, g_keyblock->key_block_size,
596 signpub_key, (0 == signpub_key)))
597 Fatal("Error verifying key block.\n");
Will Drewry9342f882010-10-26 10:22:05 -0500598
Randall Spangler7d6898d2010-06-11 09:22:13 -0700599 printf("Key block:\n");
Bill Richardson72e344d2012-03-19 12:47:18 -0700600 data_key = &g_keyblock->data_key;
601 if (opt_verbose)
602 printf(" Signature: %s\n", signpub_key ? "valid" : "ignored");
603 printf(" Size: 0x%" PRIx64 "\n", g_keyblock->key_block_size);
604 printf(" Flags: %" PRIu64 " ", g_keyblock->key_block_flags);
605 if (g_keyblock->key_block_flags & KEY_BLOCK_FLAG_DEVELOPER_0)
Bill Richardson60bcbe32010-09-09 14:53:56 -0700606 printf(" !DEV");
Bill Richardson72e344d2012-03-19 12:47:18 -0700607 if (g_keyblock->key_block_flags & KEY_BLOCK_FLAG_DEVELOPER_1)
Bill Richardson60bcbe32010-09-09 14:53:56 -0700608 printf(" DEV");
Bill Richardson72e344d2012-03-19 12:47:18 -0700609 if (g_keyblock->key_block_flags & KEY_BLOCK_FLAG_RECOVERY_0)
Bill Richardson60bcbe32010-09-09 14:53:56 -0700610 printf(" !REC");
Bill Richardson72e344d2012-03-19 12:47:18 -0700611 if (g_keyblock->key_block_flags & KEY_BLOCK_FLAG_RECOVERY_1)
Bill Richardson60bcbe32010-09-09 14:53:56 -0700612 printf(" REC");
613 printf("\n");
Randall Spangler7d6898d2010-06-11 09:22:13 -0700614 printf(" Data key algorithm: %" PRIu64 " %s\n", data_key->algorithm,
615 (data_key->algorithm < kNumAlgorithms ?
616 algo_strings[data_key->algorithm] : "(invalid)"));
617 printf(" Data key version: %" PRIu64 "\n", data_key->key_version);
Bill Richardson60bcbe32010-09-09 14:53:56 -0700618 printf(" Data key sha1sum: ");
619 PrintPubKeySha1Sum(data_key);
620 printf("\n");
Randall Spangler7d6898d2010-06-11 09:22:13 -0700621
Bill Richardson72e344d2012-03-19 12:47:18 -0700622 if (keyblock_outfile) {
623 FILE* f = NULL;
624 f = fopen(keyblock_outfile, "wb");
625 if (!f)
626 Fatal("Can't open key block file %s\n", keyblock_outfile);
627 if (1 != fwrite(g_keyblock, g_keyblock->key_block_size, 1, f))
628 Fatal("Can't write key block file %s\n", keyblock_outfile);
629 fclose(f);
630 }
631
632 if (data_key->key_version < (min_version >> 16))
633 Fatal("Data key version %" PRIu64
Randall Spangler32a65262011-06-27 10:49:11 -0700634 " is lower than minimum %" PRIu64".\n",
635 data_key->key_version, (min_version >> 16));
Randall Spanglerae87b922011-05-12 13:27:28 -0700636
Bill Richardson72e344d2012-03-19 12:47:18 -0700637 rsa = PublicKeyToRSA(data_key);
638 if (!rsa)
639 Fatal("Error parsing data key.\n");
Randall Spangler7d6898d2010-06-11 09:22:13 -0700640
641 /* Verify preamble */
Bill Richardson72e344d2012-03-19 12:47:18 -0700642 if (0 != VerifyKernelPreamble(
643 g_preamble, g_preamble->preamble_size, rsa))
644 Fatal("Error verifying preamble.\n");
Randall Spangler7d6898d2010-06-11 09:22:13 -0700645
646 printf("Preamble:\n");
Bill Richardson72e344d2012-03-19 12:47:18 -0700647 printf(" Size: 0x%" PRIx64 "\n", g_preamble->preamble_size);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700648 printf(" Header version: %" PRIu32 ".%" PRIu32"\n",
Bill Richardson72e344d2012-03-19 12:47:18 -0700649 g_preamble->header_version_major, g_preamble->header_version_minor);
650 printf(" Kernel version: %" PRIu64 "\n", g_preamble->kernel_version);
651 printf(" Body load address: 0x%" PRIx64 "\n",
652 g_preamble->body_load_address);
Bill Richardson249677d2010-06-23 11:16:37 -0700653 printf(" Body size: 0x%" PRIx64 "\n",
Bill Richardson72e344d2012-03-19 12:47:18 -0700654 g_preamble->body_signature.data_size);
Randall Spangler87c13d82010-07-19 10:35:40 -0700655 printf(" Bootloader address: 0x%" PRIx64 "\n",
Bill Richardson72e344d2012-03-19 12:47:18 -0700656 g_preamble->bootloader_address);
657 printf(" Bootloader size: 0x%" PRIx64 "\n",
658 g_preamble->bootloader_size);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700659
Bill Richardson72e344d2012-03-19 12:47:18 -0700660 if (g_preamble->kernel_version < (min_version & 0xFFFF))
661 Fatal("Kernel version %" PRIu64 " is lower than minimum %" PRIu64 ".\n",
662 g_preamble->kernel_version, (min_version & 0xFFFF));
Randall Spanglerae87b922011-05-12 13:27:28 -0700663
Randall Spangler7d6898d2010-06-11 09:22:13 -0700664 /* Verify body */
Bill Richardson72e344d2012-03-19 12:47:18 -0700665 if (0 != VerifyData(kernel_blob, kernel_size,
666 &g_preamble->body_signature, rsa))
667 Fatal("Error verifying kernel body.\n");
Randall Spangler7d6898d2010-06-11 09:22:13 -0700668 printf("Body verification succeeded.\n");
vbendebb2b0fcc2010-07-15 15:09:47 -0700669
vbendebb2b0fcc2010-07-15 15:09:47 -0700670
Bill Richardson72e344d2012-03-19 12:47:18 -0700671 if (opt_verbose)
672 printf("Config:\n%s\n", kernel_blob + CmdLineOffset(g_preamble));
vbendebb2b0fcc2010-07-15 15:09:47 -0700673
Bill Richardson72e344d2012-03-19 12:47:18 -0700674 return 0;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700675}
676
Bill Richardson72e344d2012-03-19 12:47:18 -0700677/****************************************************************************/
Randall Spangler7d6898d2010-06-11 09:22:13 -0700678
679int main(int argc, char* argv[]) {
Randall Spangler7d6898d2010-06-11 09:22:13 -0700680 char* filename = NULL;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700681 char* oldfile = NULL;
Bill Richardson72e344d2012-03-19 12:47:18 -0700682 char* keyblock_file = NULL;
683 char* signpubkey_file = NULL;
684 char* signprivkey_file = NULL;
685 char* version_str = NULL;
vbendeb00b90882010-10-21 13:46:16 -0700686 int version = -1;
Bill Richardson72e344d2012-03-19 12:47:18 -0700687 char* vmlinuz_file = NULL;
688 char* bootloader_file = NULL;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700689 char* config_file = NULL;
Bill Richardson72e344d2012-03-19 12:47:18 -0700690 arch_t arch = ARCH_X86;
691 char *address_str = NULL;
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +0800692 uint64_t kernel_body_load_address = CROS_32BIT_ENTRY_ADDR;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700693 int mode = 0;
694 int parse_error = 0;
Randall Spanglerae87b922011-05-12 13:27:28 -0700695 uint64_t min_version = 0;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700696 char* e;
Bill Richardson72e344d2012-03-19 12:47:18 -0700697 int i;
698 VbPrivateKey* signpriv_key = NULL;
699 VbPublicKey* signpub_key = NULL;
700 uint8_t* kernel_blob = NULL;
701 uint64_t kernel_size = 0;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700702
703 char *progname = strrchr(argv[0], '/');
704 if (progname)
705 progname++;
706 else
707 progname = argv[0];
708
vbendebb2b0fcc2010-07-15 15:09:47 -0700709 while (((i = getopt_long(argc, argv, ":", long_opts, NULL)) != -1) &&
710 !parse_error) {
Randall Spangler7d6898d2010-06-11 09:22:13 -0700711 switch (i) {
Bill Richardson72e344d2012-03-19 12:47:18 -0700712 default:
713 case '?':
714 /* Unhandled option */
715 parse_error = 1;
716 break;
717
718 case 0:
719 /* silently handled option */
720 break;
721
722 case OPT_MODE_PACK:
723 case OPT_MODE_REPACK:
724 case OPT_MODE_VERIFY:
725 if (mode && (mode != i)) {
726 fprintf(stderr, "Only a single mode can be specified\n");
Randall Spangler7d6898d2010-06-11 09:22:13 -0700727 parse_error = 1;
728 break;
Bill Richardson72e344d2012-03-19 12:47:18 -0700729 }
730 mode = i;
731 filename = optarg;
732 break;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700733
Bill Richardson72e344d2012-03-19 12:47:18 -0700734 case OPT_ARCH:
735 /* check the first 3 characters to also detect x86_64 */
736 if ((!strncasecmp(optarg, "x86", 3)) ||
737 (!strcasecmp(optarg, "amd64")))
738 arch = ARCH_X86;
739 else if (!strcasecmp(optarg, "arm"))
740 arch = ARCH_ARM;
741 else {
742 fprintf(stderr, "Unknown architecture string: %s\n", optarg);
743 parse_error = 1;
744 }
745 break;
Bill Richardson4f36ef32010-08-09 17:50:14 -0700746
Bill Richardson72e344d2012-03-19 12:47:18 -0700747 case OPT_OLDBLOB:
748 oldfile = optarg;
749 break;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700750
Bill Richardson72e344d2012-03-19 12:47:18 -0700751 case OPT_KLOADADDR:
752 address_str = optarg;
753 kernel_body_load_address = strtoul(optarg, &e, 0);
754 if (!*optarg || (e && *e)) {
755 fprintf(stderr, "Invalid --kloadaddr\n");
756 parse_error = 1;
757 }
758 break;
Che-Liang Chiou03762032011-02-22 11:16:51 +0800759
Bill Richardson72e344d2012-03-19 12:47:18 -0700760 case OPT_KEYBLOCK:
761 keyblock_file = optarg;
762 break;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700763
Bill Richardson72e344d2012-03-19 12:47:18 -0700764 case OPT_SIGNPUBKEY:
765 signpubkey_file = optarg;
766 break;
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +0800767
Bill Richardson72e344d2012-03-19 12:47:18 -0700768 case OPT_SIGNPRIVATE:
769 signprivkey_file = optarg;
770 break;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700771
Bill Richardson72e344d2012-03-19 12:47:18 -0700772 case OPT_VMLINUZ:
773 vmlinuz_file = optarg;
774 break;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700775
Bill Richardson72e344d2012-03-19 12:47:18 -0700776 case OPT_BOOTLOADER:
777 bootloader_file = optarg;
778 break;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700779
Bill Richardson72e344d2012-03-19 12:47:18 -0700780 case OPT_CONFIG:
781 config_file = optarg;
782 break;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700783
Bill Richardson72e344d2012-03-19 12:47:18 -0700784 case OPT_VBLOCKONLY:
785 opt_vblockonly = 1;
786 break;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700787
Bill Richardson72e344d2012-03-19 12:47:18 -0700788 case OPT_VERSION:
789 version_str = optarg;
790 version = strtoul(optarg, &e, 0);
791 if (!*optarg || (e && *e)) {
792 fprintf(stderr, "Invalid --version\n");
793 parse_error = 1;
794 }
795 break;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700796
Bill Richardson72e344d2012-03-19 12:47:18 -0700797 case OPT_MINVERSION:
798 min_version = strtoul(optarg, &e, 0);
799 if (!*optarg || (e && *e)) {
800 fprintf(stderr, "Invalid --minversion\n");
801 parse_error = 1;
802 }
803 break;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700804
Bill Richardson72e344d2012-03-19 12:47:18 -0700805 case OPT_PAD:
806 opt_pad = strtoul(optarg, &e, 0);
807 if (!*optarg || (e && *e)) {
808 fprintf(stderr, "Invalid --pad\n");
809 parse_error = 1;
810 }
811 break;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700812 }
813 }
814
815 if (parse_error)
Bill Richardsona08b5c92010-06-30 21:59:43 -0700816 return PrintHelp(progname);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700817
818 switch(mode) {
Bill Richardson72e344d2012-03-19 12:47:18 -0700819 case OPT_MODE_PACK:
Bill Richardsona08b5c92010-06-30 21:59:43 -0700820
Bill Richardson72e344d2012-03-19 12:47:18 -0700821 /* Required */
vbendebb2b0fcc2010-07-15 15:09:47 -0700822
Bill Richardson72e344d2012-03-19 12:47:18 -0700823 if (!keyblock_file)
824 Fatal("Missing required keyblock file.\n");
Bill Richardsona08b5c92010-06-30 21:59:43 -0700825
Bill Richardson72e344d2012-03-19 12:47:18 -0700826 g_keyblock = (VbKeyBlockHeader*)ReadFile(keyblock_file, 0);
827 if (!g_keyblock)
828 Fatal("Error reading key block.\n");
Bill Richardsona08b5c92010-06-30 21:59:43 -0700829
Bill Richardson72e344d2012-03-19 12:47:18 -0700830 if (!signprivkey_file)
831 Fatal("Missing required signprivate file.\n");
832
833 signpriv_key = PrivateKeyRead(signprivkey_file);
834 if (!signpriv_key)
835 Fatal("Error reading signing key.\n");
836
837 /* Optional */
838
839 if (config_file) {
840 Debug("Reading %s\n", config_file);
841 g_config_data = ReadConfigFile(config_file, &g_config_size);
842 }
843
844 if (vmlinuz_file)
845 if (!ImportVmlinuzFile(vmlinuz_file, arch, kernel_body_load_address))
846 Fatal("Error reading kernel file.\n");
847
848 if (bootloader_file) {
849 Debug("Reading %s\n", bootloader_file);
850 g_bootloader_data = ReadFile(bootloader_file, &g_bootloader_size);
851 if (!g_bootloader_data)
852 Fatal("Error reading bootloader file.\n");
853 Debug(" bootloader file size=0x%" PRIx64 "\n", g_bootloader_size);
854 }
855
856 /* Do it */
857
858 kernel_blob = CreateKernelBlob(kernel_body_load_address, arch,
859 &kernel_size);
860
861 return Pack(filename, kernel_blob, kernel_size,
862 version, kernel_body_load_address,
863 signpriv_key);
864
865 case OPT_MODE_REPACK:
866
867 /* Required */
868
869 if (!signprivkey_file)
870 Fatal("Missing required signprivate file.\n");
871
872 signpriv_key = PrivateKeyRead(signprivkey_file);
873 if (!signpriv_key)
874 Fatal("Error reading signing key.\n");
875
876 if (!oldfile)
877 Fatal("Missing previously packed blob.\n");
878
879 /* Load the old blob */
880
881 kernel_blob = ReadOldBlobFromFileOrDie(oldfile, &kernel_size);
882 if (0 != Verify(kernel_blob, kernel_size, 0, 0, 0))
883 Fatal("The oldblob doesn't verify\n");
884
885 /* Take it apart */
886
887 UnpackKernelBlob(kernel_blob, kernel_size);
888 free(kernel_blob);
889
890 /* Load optional params */
891
892 if (!version_str)
893 version = g_preamble->kernel_version;
894
895 if (!address_str)
896 kernel_body_load_address = g_preamble->body_load_address;
897
898 if (config_file) {
899 if (g_config_data)
900 free(g_config_data);
901 Debug("Reading %s\n", config_file);
902 g_config_data = ReadConfigFile(config_file, &g_config_size);
903 }
904
905 if (keyblock_file) {
906 if (g_keyblock)
907 free(g_keyblock);
908 g_keyblock = (VbKeyBlockHeader*)ReadFile(keyblock_file, 0);
909 if (!g_keyblock)
910 Fatal("Error reading key block.\n");
911 }
912
913 /* Put it back together */
914
915 kernel_blob = CreateKernelBlob(kernel_body_load_address, arch,
916 &kernel_size);
917
918 return Pack(filename, kernel_blob, kernel_size,
919 version, kernel_body_load_address,
920 signpriv_key);
921
922
923 case OPT_MODE_VERIFY:
924
925 /* Optional */
926
927 if (signpubkey_file) {
928 signpub_key = PublicKeyRead(signpubkey_file);
929 if (!signpub_key)
930 Fatal("Error reading public key.\n");
931 }
932
933 /* Do it */
934
935 kernel_blob = ReadOldBlobFromFileOrDie(filename, &kernel_size);
936
937 return Verify(kernel_blob, kernel_size, signpub_key,
938 keyblock_file, min_version);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700939 }
Bill Richardson72e344d2012-03-19 12:47:18 -0700940
941 fprintf(stderr, "You must specify a mode: --pack, --repack or --verify\n");
942 return PrintHelp(progname);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700943}