blob: f75d8a7cdc27ef42f049efc2120fff0bb60a834d [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
161static void Warning(const char *format, ...) {
162 va_list ap;
163 va_start(ap, format);
164 fprintf(stderr, "WARNING: ");
165 vfprintf(stderr, format, ap);
166 va_end(ap);
167}
168
Randall Spangler32a65262011-06-27 10:49:11 -0700169
Bill Richardson2f6a71f2010-10-14 09:25:39 -0700170/* Return an explanation when fread() fails. */
171static const char *error_fread(FILE *fp) {
172 const char *retval = "beats me why";
173 if (feof(fp))
174 retval = "EOF";
175 else if (ferror(fp))
176 retval = strerror(errno);
177 clearerr(fp);
178 return retval;
179}
Randall Spangler7d6898d2010-06-11 09:22:13 -0700180
181/* Return the smallest integral multiple of [alignment] that is equal
182 * to or greater than [val]. Used to determine the number of
183 * pages/sectors/blocks/whatever needed to contain [val]
184 * items/bytes/etc. */
185static uint64_t roundup(uint64_t val, uint64_t alignment) {
186 uint64_t rem = val % alignment;
187 if ( rem )
188 return val + (alignment - rem);
189 return val;
190}
191
192
193/* Match regexp /\b--\b/ to delimit the start of the kernel commandline. If we
194 * don't find one, we'll use the whole thing. */
195static unsigned int find_cmdline_start(char *input, unsigned int max_len) {
196 int start = 0;
197 int i;
198 for(i = 0; i < max_len - 1 && input[i]; i++) {
199 if ('-' == input[i] && '-' == input[i + 1]) { /* found a "--" */
200 if ((i == 0 || ' ' == input[i - 1]) && /* nothing before it */
201 (i + 2 >= max_len || ' ' == input[i+2])) { /* nothing after it */
202 start = i+2; /* note: hope there's a trailing '\0' */
203 break;
204 }
205 }
206 }
207 while(' ' == input[start]) /* skip leading spaces */
208 start++;
209
210 return start;
211}
212
213
Bill Richardson72e344d2012-03-19 12:47:18 -0700214/****************************************************************************/
215/* Here are globals containing all the bits & pieces I'm working on. */
216
217/* The individual parts that go into the kernel blob */
218uint8_t *g_kernel_data;
219uint64_t g_kernel_size;
220uint8_t *g_param_data;
221uint64_t g_param_size;
222uint8_t *g_config_data;
223uint64_t g_config_size;
224uint8_t *g_bootloader_data;
225uint64_t g_bootloader_size;
226uint64_t g_bootloader_address;
Bill Richardsonc8b9ca62012-03-14 10:54:05 -0700227
228
Bill Richardson72e344d2012-03-19 12:47:18 -0700229/* The individual parts of the verification blob (including the data that
230 * immediately follows the headers) */
231VbKeyBlockHeader* g_keyblock;
232VbKernelPreambleHeader* g_preamble;
vbendebb2b0fcc2010-07-15 15:09:47 -0700233
Bill Richardson72e344d2012-03-19 12:47:18 -0700234/****************************************************************************/
Bill Richardsona08b5c92010-06-30 21:59:43 -0700235
vbendebb2b0fcc2010-07-15 15:09:47 -0700236/*
237 * Read the kernel command line from a file. Get rid of \n characters along
238 * the way and verify that the line fits into a 4K buffer.
239 *
240 * Return the buffer contaning the line on success (and set the line length
241 * using the passed in parameter), or NULL in case something goes wrong.
242 */
243static uint8_t* ReadConfigFile(const char* config_file, uint64_t* config_size)
244{
245 uint8_t* config_buf;
246 int ii;
247
248 config_buf = ReadFile(config_file, config_size);
249 Debug(" config file size=0x%" PRIx64 "\n", *config_size);
250 if (CROS_CONFIG_SIZE <= *config_size) { /* need room for trailing '\0' */
Randall Spangler32a65262011-06-27 10:49:11 -0700251 VbExError("Config file %s is too large (>= %d bytes)\n",
252 config_file, CROS_CONFIG_SIZE);
vbendebb2b0fcc2010-07-15 15:09:47 -0700253 return NULL;
254 }
255
256 /* Replace newlines with spaces */
257 for (ii = 0; ii < *config_size; ii++) {
258 if ('\n' == config_buf[ii]) {
259 config_buf[ii] = ' ';
260 }
261 }
262 return config_buf;
263}
264
Bill Richardson72e344d2012-03-19 12:47:18 -0700265
266/* Offset of kernel command line string from start of packed kernel blob */
267static uint64_t CmdLineOffset(VbKernelPreambleHeader *preamble) {
268 return preamble->bootloader_address - preamble->body_load_address -
269 CROS_CONFIG_SIZE - CROS_PARAMS_SIZE;
270}
271
272/* This initializes g_vmlinuz and g_param from a standard vmlinuz file.
273 * It returns 0 on error. */
274static int ImportVmlinuzFile(const char *vmlinuz_file, arch_t arch,
275 uint64_t kernel_body_load_address) {
276 uint8_t *kernel_buf;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700277 uint64_t kernel_size;
278 uint64_t kernel32_start = 0;
279 uint64_t kernel32_size = 0;
Bill Richardson72e344d2012-03-19 12:47:18 -0700280 struct linux_kernel_header* lh = 0;
281 struct linux_kernel_params* params = 0;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700282
283 /* Read the kernel */
Bill Richardson72e344d2012-03-19 12:47:18 -0700284 Debug("Reading %s\n", vmlinuz_file);
285 kernel_buf = ReadFile(vmlinuz_file, &kernel_size);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700286 if (!kernel_buf)
Bill Richardsona08b5c92010-06-30 21:59:43 -0700287 return 0;
Bill Richardson249677d2010-06-23 11:16:37 -0700288 Debug(" kernel file size=0x%" PRIx64 "\n", kernel_size);
Bill Richardson72e344d2012-03-19 12:47:18 -0700289 if (!kernel_size)
290 Fatal("Empty kernel file\n");
291
292 /* Go ahead and allocate the param region anyway. I don't think we need it
293 * for non-x86, but let's keep it for now. */
294 g_param_size = CROS_PARAMS_SIZE;
295 g_param_data= VbExMalloc(g_param_size);
296 Memset(g_param_data, 0, g_param_size);
297
298 /* Unless we're handling x86, the kernel is the kernel, so we're done. */
299 if (arch != ARCH_X86) {
300 g_kernel_data = kernel_buf;
301 g_kernel_size = kernel_size;
302 return 1;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700303 }
304
Bill Richardson72e344d2012-03-19 12:47:18 -0700305 /* The first part of the x86 vmlinuz is a header, followed by a real-mode
306 * boot stub. We only want the 32-bit part. */
307 lh = (struct linux_kernel_header *)kernel_buf;
308 kernel32_start = (lh->setup_sects + 1) << 9;
309 if (kernel32_start >= kernel_size)
310 Fatal("Malformed kernel\n");
Randall Spangler7d6898d2010-06-11 09:22:13 -0700311 kernel32_size = kernel_size - kernel32_start;
Bill Richardson72e344d2012-03-19 12:47:18 -0700312
Bill Richardson249677d2010-06-23 11:16:37 -0700313 Debug(" kernel32_start=0x%" PRIx64 "\n", kernel32_start);
314 Debug(" kernel32_size=0x%" PRIx64 "\n", kernel32_size);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700315
Bill Richardson72e344d2012-03-19 12:47:18 -0700316 /* Keep just the 32-bit kernel. */
317 if (kernel32_size) {
318 g_kernel_size = kernel32_size;
319 g_kernel_data = VbExMalloc(g_kernel_size);
320 Memcpy(g_kernel_data, kernel_buf + kernel32_start, kernel32_size);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700321 }
Randall Spangler7d6898d2010-06-11 09:22:13 -0700322
Bill Richardson72e344d2012-03-19 12:47:18 -0700323 /* Copy the original zeropage data from kernel_buf into g_param_data, then
324 * tweak a few fields for our purposes */
325 params = (struct linux_kernel_params *)(g_param_data);
326 Memcpy(&(params->setup_sects), &(lh->setup_sects),
327 sizeof(*lh) - offsetof(struct linux_kernel_header, setup_sects));
Randall Spangler7d6898d2010-06-11 09:22:13 -0700328 params->boot_flag = 0;
Bill Richardson72e344d2012-03-19 12:47:18 -0700329 params->ramdisk_image = 0; /* we don't support initrd */
Randall Spangler7d6898d2010-06-11 09:22:13 -0700330 params->ramdisk_size = 0;
331 params->type_of_loader = 0xff;
Bill Richardson72e344d2012-03-19 12:47:18 -0700332 /* We need to point to the kernel commandline arg. On disk, it will come
333 * right after the 32-bit part of the kernel. */
334 params->cmd_line_ptr = kernel_body_load_address +
335 roundup(kernel32_size, CROS_ALIGN) +
336 find_cmdline_start((char *)g_config_data, g_config_size);
337 Debug(" cmdline_addr=0x%x\n", params->cmd_line_ptr);
Che-Liang Chiou475bf442010-08-23 11:20:44 +0800338 /* 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 Richardson72e344d2012-03-19 12:47:18 -0700347 /* done */
Randall Spangler32a65262011-06-27 10:49:11 -0700348 free(kernel_buf);
Bill Richardson72e344d2012-03-19 12:47:18 -0700349 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. */
354static uint8_t* ReadOldBlobFromFileOrDie(const char *filename,
355 uint64_t* size_ptr) {
vbendebb2b0fcc2010-07-15 15:09:47 -0700356 FILE* fp = NULL;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700357 struct stat statbuf;
358 VbKeyBlockHeader* key_block;
359 VbKernelPreambleHeader* preamble;
360 uint64_t now = 0;
Bill Richardson72e344d2012-03-19 12:47:18 -0700361 uint8_t* buf;
362 uint8_t* kernel_blob_data;
363 uint64_t kernel_blob_size;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700364
Bill Richardson72e344d2012-03-19 12:47:18 -0700365 if (0 != stat(filename, &statbuf))
366 Fatal("Unable to stat %s: %s\n", filename, strerror(errno));
Bill Richardsona08b5c92010-06-30 21:59:43 -0700367
368 Debug("%s size is 0x%" PRIx64 "\n", filename, statbuf.st_size);
Bill Richardson72e344d2012-03-19 12:47:18 -0700369 if (statbuf.st_size < opt_pad)
370 Fatal("%s is too small to be a valid kernel blob\n");
Bill Richardsona08b5c92010-06-30 21:59:43 -0700371
372 Debug("Reading %s\n", filename);
373 fp = fopen(filename, "rb");
Bill Richardson72e344d2012-03-19 12:47:18 -0700374 if (!fp)
375 Fatal("Unable to open file %s: %s\n", filename, strerror(errno));
Bill Richardsona08b5c92010-06-30 21:59:43 -0700376
Bill Richardson72e344d2012-03-19 12:47:18 -0700377 buf = VbExMalloc(opt_pad);
378 if (1 != fread(buf, opt_pad, 1, fp))
379 Fatal("Unable to read header from %s: %s\n", filename, error_fread(fp));
vbendebb2b0fcc2010-07-15 15:09:47 -0700380
Bill Richardson72e344d2012-03-19 12:47:18 -0700381 /* Sanity-check the key_block */
Bill Richardsona08b5c92010-06-30 21:59:43 -0700382 key_block = (VbKeyBlockHeader*)buf;
383 Debug("Keyblock is 0x%" PRIx64 " bytes\n", key_block->key_block_size);
384 now += key_block->key_block_size;
Bill Richardson72e344d2012-03-19 12:47:18 -0700385 if (now > statbuf.st_size)
386 Fatal("key_block_size advances past the end of the blob\n");
387 if (now > opt_pad)
388 Fatal("key_block_size advances past %" PRIu64 " byte padding\n",
389 opt_pad);
390 /* LGTM */
391 g_keyblock = (VbKeyBlockHeader*)VbExMalloc(key_block->key_block_size);
392 Memcpy(g_keyblock, key_block, key_block->key_block_size);
Bill Richardsona08b5c92010-06-30 21:59:43 -0700393
Bill Richardson72e344d2012-03-19 12:47:18 -0700394 /* And the preamble */
Bill Richardsona08b5c92010-06-30 21:59:43 -0700395 preamble = (VbKernelPreambleHeader*)(buf + now);
396 Debug("Preamble is 0x%" PRIx64 " bytes\n", preamble->preamble_size);
397 now += preamble->preamble_size;
Bill Richardson72e344d2012-03-19 12:47:18 -0700398 if (now > statbuf.st_size)
399 Fatal("preamble_size advances past the end of the blob\n");
400 if (now > opt_pad)
401 Fatal("preamble_size advances past %" PRIu64 " byte padding\n",
402 opt_pad);
403 /* LGTM */
404 Debug(" kernel_version = %d\n", preamble->kernel_version);
405 Debug(" bootloader_address = 0x%" PRIx64 "\n", preamble->bootloader_address);
406 Debug(" bootloader_size = 0x%" PRIx64 "\n", preamble->bootloader_size);
407 Debug(" kern_blob_size = 0x%" PRIx64 "\n",
408 preamble->body_signature.data_size);
409 g_preamble = (VbKernelPreambleHeader*)VbExMalloc(preamble->preamble_size);
410 Memcpy(g_preamble, preamble, preamble->preamble_size);
Bill Richardsona08b5c92010-06-30 21:59:43 -0700411
Bill Richardson72e344d2012-03-19 12:47:18 -0700412 /* Now for the kernel blob */
Bill Richardsona08b5c92010-06-30 21:59:43 -0700413 Debug("kernel blob is at offset 0x%" PRIx64 "\n", now);
Bill Richardson72e344d2012-03-19 12:47:18 -0700414 if (0 != fseek(fp, now, SEEK_SET))
415 Fatal("Unable to seek to 0x%" PRIx64 " in %s: %s\n", now, filename,
Bill Richardsona08b5c92010-06-30 21:59:43 -0700416 strerror(errno));
Bill Richardsona08b5c92010-06-30 21:59:43 -0700417
Bill Richardson72e344d2012-03-19 12:47:18 -0700418 /* Sanity check */
419 kernel_blob_size = statbuf.st_size - now;
420 if (!kernel_blob_size)
421 Fatal("No kernel blob found\n");
422 if (kernel_blob_size < preamble->body_signature.data_size)
423 fprintf(stderr, "Warning: kernel file only has 0x%" PRIx64 " bytes\n",
424 kernel_blob_size);
425 kernel_blob_data = VbExMalloc(kernel_blob_size);
Bill Richardsona08b5c92010-06-30 21:59:43 -0700426
Bill Richardson72e344d2012-03-19 12:47:18 -0700427 /* Read it in */
428 if (1 != fread(kernel_blob_data, kernel_blob_size, 1, fp))
429 Fatal("Unable to read kernel blob from %s: %s\n", filename,
Randall Spangler32a65262011-06-27 10:49:11 -0700430 error_fread(fp));
Bill Richardsona08b5c92010-06-30 21:59:43 -0700431
Bill Richardson72e344d2012-03-19 12:47:18 -0700432 /* Done */
433 VbExFree(buf);
Bill Richardsona08b5c92010-06-30 21:59:43 -0700434
Bill Richardson72e344d2012-03-19 12:47:18 -0700435 if (size_ptr)
436 *size_ptr = kernel_blob_size;
437
438 return kernel_blob_data;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700439}
440
441
Bill Richardson72e344d2012-03-19 12:47:18 -0700442/* Split a kernel blob into separate g_kernel, g_param, g_config, and
443 * g_bootloader parts. */
444static void UnpackKernelBlob(uint8_t *kernel_blob_data,
445 uint64_t kernel_blob_size) {
446
447 uint64_t k_blob_size = g_preamble->body_signature.data_size;
448 uint64_t k_blob_ofs = 0;
449 uint64_t b_size = g_preamble->bootloader_size;
450 uint64_t b_ofs = k_blob_ofs + g_preamble->bootloader_address -
451 g_preamble->body_load_address;
452 uint64_t p_ofs = b_ofs - CROS_CONFIG_SIZE;
453 uint64_t c_ofs = p_ofs - CROS_PARAMS_SIZE;
454 uint64_t k_size = c_ofs;
455
456 Debug("k_blob_size = 0x%" PRIx64 "\n", k_blob_size );
457 Debug("k_blob_ofs = 0x%" PRIx64 "\n", k_blob_ofs );
458 Debug("b_size = 0x%" PRIx64 "\n", b_size );
459 Debug("b_ofs = 0x%" PRIx64 "\n", b_ofs );
460 Debug("p_ofs = 0x%" PRIx64 "\n", p_ofs );
461 Debug("c_ofs = 0x%" PRIx64 "\n", c_ofs );
462
463 g_kernel_size = c_ofs;
464 g_kernel_data = VbExMalloc(g_kernel_size);
465 Memcpy(g_kernel_data, kernel_blob_data, g_kernel_size);
466
467 g_param_size = CROS_PARAMS_SIZE;
468 g_param_data = VbExMalloc(g_param_size);
469 Memcpy(g_param_data, kernel_blob_data + p_ofs, g_param_size);
470
471 g_config_size = CROS_CONFIG_SIZE;
472 g_config_data = VbExMalloc(g_config_size);
473 Memcpy(g_config_data, kernel_blob_data + c_ofs, g_config_size);
474
475 g_bootloader_size = b_size;
476 g_bootloader_data = VbExMalloc(g_bootloader_size);
477 Memcpy(g_bootloader_data, kernel_blob_data + b_ofs, g_bootloader_size);
478}
479
480
481
482/****************************************************************************/
483
484static uint8_t* CreateKernelBlob(uint64_t kernel_body_load_address,
485 arch_t arch,
486 uint64_t *size_ptr) {
487 uint8_t *kern_blob;
488 uint64_t kern_blob_size;
489 uint64_t now;
490 uint64_t bootloader_size = roundup(g_bootloader_size, CROS_ALIGN);
491
492 /* Put the kernel blob together */
493 kern_blob_size = roundup(g_kernel_size, CROS_ALIGN) +
494 CROS_CONFIG_SIZE + CROS_PARAMS_SIZE + bootloader_size;
495 Debug("kern_blob_size=0x%" PRIx64 "\n", kern_blob_size);
496 kern_blob = VbExMalloc(kern_blob_size);
497 Memset(kern_blob, 0, kern_blob_size);
498 now = 0;
499
500 Debug("kernel goes at kern_blob+0x%" PRIx64 "\n", now);
501
502 Memcpy(kern_blob+now, g_kernel_data, g_kernel_size);
503 now += roundup(g_kernel_size, CROS_ALIGN);
504
505 Debug("config goes at kern_blob+0x%" PRIx64 "\n", now);
506 if (g_config_size)
507 Memcpy(kern_blob + now, g_config_data, g_config_size);
508 now += CROS_CONFIG_SIZE;
509
510 Debug("params goes at kern_blob+0x%" PRIx64 "\n", now);
511 if (g_param_size) {
512 Memcpy(kern_blob + now, g_param_data, g_param_size);
513 }
514 now += CROS_PARAMS_SIZE;
515
516 Debug("bootloader goes at kern_blob+0x%" PRIx64 "\n", now);
517 g_bootloader_address = kernel_body_load_address + now;
518 Debug(" bootloader_address=0x%" PRIx64 "\n", g_bootloader_address);
519 Debug(" bootloader_size=0x%" PRIx64 "\n", bootloader_size);
520 if (bootloader_size)
521 Memcpy(kern_blob + now, g_bootloader_data, g_bootloader_size);
522 now += bootloader_size;
523 Debug("end of kern_blob at kern_blob+0x%" PRIx64 "\n", now);
524
525 /* Done */
526 if (size_ptr)
527 *size_ptr = kern_blob_size;
528
529 return kern_blob;
530}
531
532static int Pack(const char* outfile,
533 uint8_t *kernel_blob,
534 uint64_t kernel_size,
535 int version,
536 uint64_t kernel_body_load_address,
537 VbPrivateKey* signpriv_key) {
Bill Richardsona08b5c92010-06-30 21:59:43 -0700538 VbSignature* body_sig;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700539 uint64_t key_block_size;
540 FILE* f;
541 uint64_t i;
Bill Richardsonc8b9ca62012-03-14 10:54:05 -0700542 uint64_t written = 0;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700543
Randall Spangler7d6898d2010-06-11 09:22:13 -0700544 /* Sign the kernel data */
Bill Richardson72e344d2012-03-19 12:47:18 -0700545 body_sig = CalculateSignature(kernel_blob, kernel_size, signpriv_key);
546 if (!body_sig)
547 Fatal("Error calculating body signature\n");
Randall Spangler7d6898d2010-06-11 09:22:13 -0700548
549 /* Create preamble */
Bill Richardson72e344d2012-03-19 12:47:18 -0700550 g_preamble = CreateKernelPreamble(version,
551 kernel_body_load_address,
552 g_bootloader_address,
553 roundup(g_bootloader_size, CROS_ALIGN),
554 body_sig,
555 opt_pad - g_keyblock->key_block_size,
556 signpriv_key);
557 if (!g_preamble) {
Randall Spangler32a65262011-06-27 10:49:11 -0700558 VbExError("Error creating preamble.\n");
Randall Spangler7d6898d2010-06-11 09:22:13 -0700559 return 1;
560 }
Randall Spangler7d6898d2010-06-11 09:22:13 -0700561 /* Write the output file */
Bill Richardson249677d2010-06-23 11:16:37 -0700562 Debug("writing %s...\n", outfile);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700563 f = fopen(outfile, "wb");
564 if (!f) {
Randall Spangler32a65262011-06-27 10:49:11 -0700565 VbExError("Can't open output file %s\n", outfile);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700566 return 1;
567 }
Bill Richardson72e344d2012-03-19 12:47:18 -0700568 Debug("0x%" PRIx64 " bytes of key_block\n", g_keyblock->key_block_size);
569 Debug("0x%" PRIx64 " bytes of preamble\n", g_preamble->preamble_size);
570 i = ((1 != fwrite(g_keyblock, g_keyblock->key_block_size, 1, f)) ||
571 (1 != fwrite(g_preamble, g_preamble->preamble_size, 1, f)));
Randall Spangler7d6898d2010-06-11 09:22:13 -0700572 if (i) {
Randall Spangler32a65262011-06-27 10:49:11 -0700573 VbExError("Can't write output file %s\n", outfile);
Bill Richardsona08b5c92010-06-30 21:59:43 -0700574 fclose(f);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700575 unlink(outfile);
576 return 1;
577 }
Bill Richardson72e344d2012-03-19 12:47:18 -0700578 written += g_keyblock->key_block_size;
579 written += g_preamble->preamble_size;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700580
Bill Richardson72e344d2012-03-19 12:47:18 -0700581 if (!opt_vblockonly) {
582 Debug("0x%" PRIx64 " bytes of kern_blob\n", kernel_size);
583 i = (1 != fwrite(kernel_blob, kernel_size, 1, f));
Bill Richardsona08b5c92010-06-30 21:59:43 -0700584 if (i) {
Bill Richardsona08b5c92010-06-30 21:59:43 -0700585 fclose(f);
586 unlink(outfile);
Bill Richardson72e344d2012-03-19 12:47:18 -0700587 Fatal("Can't write output file %s\n", outfile);
Bill Richardsona08b5c92010-06-30 21:59:43 -0700588 }
Bill Richardson72e344d2012-03-19 12:47:18 -0700589 written += kernel_size;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700590 }
Bill Richardsonc8b9ca62012-03-14 10:54:05 -0700591 Debug("0x%" PRIx64 " bytes total\n", written);
Bill Richardsona08b5c92010-06-30 21:59:43 -0700592 fclose(f);
593
Randall Spangler7d6898d2010-06-11 09:22:13 -0700594 /* Success */
595 return 0;
596}
597
Bill Richardson72e344d2012-03-19 12:47:18 -0700598static int Verify(uint8_t* kernel_blob,
599 uint64_t kernel_size,
600 VbPublicKey* signpub_key,
601 const char* keyblock_outfile,
602 uint64_t min_version) {
Randall Spangler7d6898d2010-06-11 09:22:13 -0700603 VbPublicKey* data_key;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700604 RSAPublicKey* rsa;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700605
Bill Richardson72e344d2012-03-19 12:47:18 -0700606 if (0 != KeyBlockVerify(g_keyblock, g_keyblock->key_block_size,
607 signpub_key, (0 == signpub_key)))
608 Fatal("Error verifying key block.\n");
Will Drewry9342f882010-10-26 10:22:05 -0500609
Randall Spangler7d6898d2010-06-11 09:22:13 -0700610 printf("Key block:\n");
Bill Richardson72e344d2012-03-19 12:47:18 -0700611 data_key = &g_keyblock->data_key;
612 if (opt_verbose)
613 printf(" Signature: %s\n", signpub_key ? "valid" : "ignored");
614 printf(" Size: 0x%" PRIx64 "\n", g_keyblock->key_block_size);
615 printf(" Flags: %" PRIu64 " ", g_keyblock->key_block_flags);
616 if (g_keyblock->key_block_flags & KEY_BLOCK_FLAG_DEVELOPER_0)
Bill Richardson60bcbe32010-09-09 14:53:56 -0700617 printf(" !DEV");
Bill Richardson72e344d2012-03-19 12:47:18 -0700618 if (g_keyblock->key_block_flags & KEY_BLOCK_FLAG_DEVELOPER_1)
Bill Richardson60bcbe32010-09-09 14:53:56 -0700619 printf(" DEV");
Bill Richardson72e344d2012-03-19 12:47:18 -0700620 if (g_keyblock->key_block_flags & KEY_BLOCK_FLAG_RECOVERY_0)
Bill Richardson60bcbe32010-09-09 14:53:56 -0700621 printf(" !REC");
Bill Richardson72e344d2012-03-19 12:47:18 -0700622 if (g_keyblock->key_block_flags & KEY_BLOCK_FLAG_RECOVERY_1)
Bill Richardson60bcbe32010-09-09 14:53:56 -0700623 printf(" REC");
624 printf("\n");
Randall Spangler7d6898d2010-06-11 09:22:13 -0700625 printf(" Data key algorithm: %" PRIu64 " %s\n", data_key->algorithm,
626 (data_key->algorithm < kNumAlgorithms ?
627 algo_strings[data_key->algorithm] : "(invalid)"));
628 printf(" Data key version: %" PRIu64 "\n", data_key->key_version);
Bill Richardson60bcbe32010-09-09 14:53:56 -0700629 printf(" Data key sha1sum: ");
630 PrintPubKeySha1Sum(data_key);
631 printf("\n");
Randall Spangler7d6898d2010-06-11 09:22:13 -0700632
Bill Richardson72e344d2012-03-19 12:47:18 -0700633 if (keyblock_outfile) {
634 FILE* f = NULL;
635 f = fopen(keyblock_outfile, "wb");
636 if (!f)
637 Fatal("Can't open key block file %s\n", keyblock_outfile);
638 if (1 != fwrite(g_keyblock, g_keyblock->key_block_size, 1, f))
639 Fatal("Can't write key block file %s\n", keyblock_outfile);
640 fclose(f);
641 }
642
643 if (data_key->key_version < (min_version >> 16))
644 Fatal("Data key version %" PRIu64
Randall Spangler32a65262011-06-27 10:49:11 -0700645 " is lower than minimum %" PRIu64".\n",
646 data_key->key_version, (min_version >> 16));
Randall Spanglerae87b922011-05-12 13:27:28 -0700647
Bill Richardson72e344d2012-03-19 12:47:18 -0700648 rsa = PublicKeyToRSA(data_key);
649 if (!rsa)
650 Fatal("Error parsing data key.\n");
Randall Spangler7d6898d2010-06-11 09:22:13 -0700651
652 /* Verify preamble */
Bill Richardson72e344d2012-03-19 12:47:18 -0700653 if (0 != VerifyKernelPreamble(
654 g_preamble, g_preamble->preamble_size, rsa))
655 Fatal("Error verifying preamble.\n");
Randall Spangler7d6898d2010-06-11 09:22:13 -0700656
657 printf("Preamble:\n");
Bill Richardson72e344d2012-03-19 12:47:18 -0700658 printf(" Size: 0x%" PRIx64 "\n", g_preamble->preamble_size);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700659 printf(" Header version: %" PRIu32 ".%" PRIu32"\n",
Bill Richardson72e344d2012-03-19 12:47:18 -0700660 g_preamble->header_version_major, g_preamble->header_version_minor);
661 printf(" Kernel version: %" PRIu64 "\n", g_preamble->kernel_version);
662 printf(" Body load address: 0x%" PRIx64 "\n",
663 g_preamble->body_load_address);
Bill Richardson249677d2010-06-23 11:16:37 -0700664 printf(" Body size: 0x%" PRIx64 "\n",
Bill Richardson72e344d2012-03-19 12:47:18 -0700665 g_preamble->body_signature.data_size);
Randall Spangler87c13d82010-07-19 10:35:40 -0700666 printf(" Bootloader address: 0x%" PRIx64 "\n",
Bill Richardson72e344d2012-03-19 12:47:18 -0700667 g_preamble->bootloader_address);
668 printf(" Bootloader size: 0x%" PRIx64 "\n",
669 g_preamble->bootloader_size);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700670
Bill Richardson72e344d2012-03-19 12:47:18 -0700671 if (g_preamble->kernel_version < (min_version & 0xFFFF))
672 Fatal("Kernel version %" PRIu64 " is lower than minimum %" PRIu64 ".\n",
673 g_preamble->kernel_version, (min_version & 0xFFFF));
Randall Spanglerae87b922011-05-12 13:27:28 -0700674
Randall Spangler7d6898d2010-06-11 09:22:13 -0700675 /* Verify body */
Bill Richardson72e344d2012-03-19 12:47:18 -0700676 if (0 != VerifyData(kernel_blob, kernel_size,
677 &g_preamble->body_signature, rsa))
678 Fatal("Error verifying kernel body.\n");
Randall Spangler7d6898d2010-06-11 09:22:13 -0700679 printf("Body verification succeeded.\n");
vbendebb2b0fcc2010-07-15 15:09:47 -0700680
vbendebb2b0fcc2010-07-15 15:09:47 -0700681
Bill Richardson72e344d2012-03-19 12:47:18 -0700682 if (opt_verbose)
683 printf("Config:\n%s\n", kernel_blob + CmdLineOffset(g_preamble));
vbendebb2b0fcc2010-07-15 15:09:47 -0700684
Bill Richardson72e344d2012-03-19 12:47:18 -0700685 return 0;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700686}
687
Bill Richardson72e344d2012-03-19 12:47:18 -0700688/****************************************************************************/
Randall Spangler7d6898d2010-06-11 09:22:13 -0700689
690int main(int argc, char* argv[]) {
Randall Spangler7d6898d2010-06-11 09:22:13 -0700691 char* filename = NULL;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700692 char* oldfile = NULL;
Bill Richardson72e344d2012-03-19 12:47:18 -0700693 char* keyblock_file = NULL;
694 char* signpubkey_file = NULL;
695 char* signprivkey_file = NULL;
696 char* version_str = NULL;
vbendeb00b90882010-10-21 13:46:16 -0700697 int version = -1;
Bill Richardson72e344d2012-03-19 12:47:18 -0700698 char* vmlinuz_file = NULL;
699 char* bootloader_file = NULL;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700700 char* config_file = NULL;
Bill Richardson72e344d2012-03-19 12:47:18 -0700701 arch_t arch = ARCH_X86;
702 char *address_str = NULL;
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +0800703 uint64_t kernel_body_load_address = CROS_32BIT_ENTRY_ADDR;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700704 int mode = 0;
705 int parse_error = 0;
Randall Spanglerae87b922011-05-12 13:27:28 -0700706 uint64_t min_version = 0;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700707 char* e;
Bill Richardson72e344d2012-03-19 12:47:18 -0700708 int i;
709 VbPrivateKey* signpriv_key = NULL;
710 VbPublicKey* signpub_key = NULL;
711 uint8_t* kernel_blob = NULL;
712 uint64_t kernel_size = 0;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700713
714 char *progname = strrchr(argv[0], '/');
715 if (progname)
716 progname++;
717 else
718 progname = argv[0];
719
vbendebb2b0fcc2010-07-15 15:09:47 -0700720 while (((i = getopt_long(argc, argv, ":", long_opts, NULL)) != -1) &&
721 !parse_error) {
Randall Spangler7d6898d2010-06-11 09:22:13 -0700722 switch (i) {
Bill Richardson72e344d2012-03-19 12:47:18 -0700723 default:
724 case '?':
725 /* Unhandled option */
726 parse_error = 1;
727 break;
728
729 case 0:
730 /* silently handled option */
731 break;
732
733 case OPT_MODE_PACK:
734 case OPT_MODE_REPACK:
735 case OPT_MODE_VERIFY:
736 if (mode && (mode != i)) {
737 fprintf(stderr, "Only a single mode can be specified\n");
Randall Spangler7d6898d2010-06-11 09:22:13 -0700738 parse_error = 1;
739 break;
Bill Richardson72e344d2012-03-19 12:47:18 -0700740 }
741 mode = i;
742 filename = optarg;
743 break;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700744
Bill Richardson72e344d2012-03-19 12:47:18 -0700745 case OPT_ARCH:
746 /* check the first 3 characters to also detect x86_64 */
747 if ((!strncasecmp(optarg, "x86", 3)) ||
748 (!strcasecmp(optarg, "amd64")))
749 arch = ARCH_X86;
750 else if (!strcasecmp(optarg, "arm"))
751 arch = ARCH_ARM;
752 else {
753 fprintf(stderr, "Unknown architecture string: %s\n", optarg);
754 parse_error = 1;
755 }
756 break;
Bill Richardson4f36ef32010-08-09 17:50:14 -0700757
Bill Richardson72e344d2012-03-19 12:47:18 -0700758 case OPT_OLDBLOB:
759 oldfile = optarg;
760 break;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700761
Bill Richardson72e344d2012-03-19 12:47:18 -0700762 case OPT_KLOADADDR:
763 address_str = optarg;
764 kernel_body_load_address = strtoul(optarg, &e, 0);
765 if (!*optarg || (e && *e)) {
766 fprintf(stderr, "Invalid --kloadaddr\n");
767 parse_error = 1;
768 }
769 break;
Che-Liang Chiou03762032011-02-22 11:16:51 +0800770
Bill Richardson72e344d2012-03-19 12:47:18 -0700771 case OPT_KEYBLOCK:
772 keyblock_file = optarg;
773 break;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700774
Bill Richardson72e344d2012-03-19 12:47:18 -0700775 case OPT_SIGNPUBKEY:
776 signpubkey_file = optarg;
777 break;
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +0800778
Bill Richardson72e344d2012-03-19 12:47:18 -0700779 case OPT_SIGNPRIVATE:
780 signprivkey_file = optarg;
781 break;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700782
Bill Richardson72e344d2012-03-19 12:47:18 -0700783 case OPT_VMLINUZ:
784 vmlinuz_file = optarg;
785 break;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700786
Bill Richardson72e344d2012-03-19 12:47:18 -0700787 case OPT_BOOTLOADER:
788 bootloader_file = optarg;
789 break;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700790
Bill Richardson72e344d2012-03-19 12:47:18 -0700791 case OPT_CONFIG:
792 config_file = optarg;
793 break;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700794
Bill Richardson72e344d2012-03-19 12:47:18 -0700795 case OPT_VBLOCKONLY:
796 opt_vblockonly = 1;
797 break;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700798
Bill Richardson72e344d2012-03-19 12:47:18 -0700799 case OPT_VERSION:
800 version_str = optarg;
801 version = strtoul(optarg, &e, 0);
802 if (!*optarg || (e && *e)) {
803 fprintf(stderr, "Invalid --version\n");
804 parse_error = 1;
805 }
806 break;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700807
Bill Richardson72e344d2012-03-19 12:47:18 -0700808 case OPT_MINVERSION:
809 min_version = strtoul(optarg, &e, 0);
810 if (!*optarg || (e && *e)) {
811 fprintf(stderr, "Invalid --minversion\n");
812 parse_error = 1;
813 }
814 break;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700815
Bill Richardson72e344d2012-03-19 12:47:18 -0700816 case OPT_PAD:
817 opt_pad = strtoul(optarg, &e, 0);
818 if (!*optarg || (e && *e)) {
819 fprintf(stderr, "Invalid --pad\n");
820 parse_error = 1;
821 }
822 break;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700823 }
824 }
825
826 if (parse_error)
Bill Richardsona08b5c92010-06-30 21:59:43 -0700827 return PrintHelp(progname);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700828
829 switch(mode) {
Bill Richardson72e344d2012-03-19 12:47:18 -0700830 case OPT_MODE_PACK:
Bill Richardsona08b5c92010-06-30 21:59:43 -0700831
Bill Richardson72e344d2012-03-19 12:47:18 -0700832 /* Required */
vbendebb2b0fcc2010-07-15 15:09:47 -0700833
Bill Richardson72e344d2012-03-19 12:47:18 -0700834 if (!keyblock_file)
835 Fatal("Missing required keyblock file.\n");
Bill Richardsona08b5c92010-06-30 21:59:43 -0700836
Bill Richardson72e344d2012-03-19 12:47:18 -0700837 g_keyblock = (VbKeyBlockHeader*)ReadFile(keyblock_file, 0);
838 if (!g_keyblock)
839 Fatal("Error reading key block.\n");
Bill Richardsona08b5c92010-06-30 21:59:43 -0700840
Bill Richardson72e344d2012-03-19 12:47:18 -0700841 if (!signprivkey_file)
842 Fatal("Missing required signprivate file.\n");
843
844 signpriv_key = PrivateKeyRead(signprivkey_file);
845 if (!signpriv_key)
846 Fatal("Error reading signing key.\n");
847
848 /* Optional */
849
850 if (config_file) {
851 Debug("Reading %s\n", config_file);
852 g_config_data = ReadConfigFile(config_file, &g_config_size);
853 }
854
855 if (vmlinuz_file)
856 if (!ImportVmlinuzFile(vmlinuz_file, arch, kernel_body_load_address))
857 Fatal("Error reading kernel file.\n");
858
859 if (bootloader_file) {
860 Debug("Reading %s\n", bootloader_file);
861 g_bootloader_data = ReadFile(bootloader_file, &g_bootloader_size);
862 if (!g_bootloader_data)
863 Fatal("Error reading bootloader file.\n");
864 Debug(" bootloader file size=0x%" PRIx64 "\n", g_bootloader_size);
865 }
866
867 /* Do it */
868
869 kernel_blob = CreateKernelBlob(kernel_body_load_address, arch,
870 &kernel_size);
871
872 return Pack(filename, kernel_blob, kernel_size,
873 version, kernel_body_load_address,
874 signpriv_key);
875
876 case OPT_MODE_REPACK:
877
878 /* Required */
879
880 if (!signprivkey_file)
881 Fatal("Missing required signprivate file.\n");
882
883 signpriv_key = PrivateKeyRead(signprivkey_file);
884 if (!signpriv_key)
885 Fatal("Error reading signing key.\n");
886
887 if (!oldfile)
888 Fatal("Missing previously packed blob.\n");
889
890 /* Load the old blob */
891
892 kernel_blob = ReadOldBlobFromFileOrDie(oldfile, &kernel_size);
893 if (0 != Verify(kernel_blob, kernel_size, 0, 0, 0))
894 Fatal("The oldblob doesn't verify\n");
895
896 /* Take it apart */
897
898 UnpackKernelBlob(kernel_blob, kernel_size);
899 free(kernel_blob);
900
901 /* Load optional params */
902
903 if (!version_str)
904 version = g_preamble->kernel_version;
905
906 if (!address_str)
907 kernel_body_load_address = g_preamble->body_load_address;
908
909 if (config_file) {
910 if (g_config_data)
911 free(g_config_data);
912 Debug("Reading %s\n", config_file);
913 g_config_data = ReadConfigFile(config_file, &g_config_size);
914 }
915
916 if (keyblock_file) {
917 if (g_keyblock)
918 free(g_keyblock);
919 g_keyblock = (VbKeyBlockHeader*)ReadFile(keyblock_file, 0);
920 if (!g_keyblock)
921 Fatal("Error reading key block.\n");
922 }
923
924 /* Put it back together */
925
926 kernel_blob = CreateKernelBlob(kernel_body_load_address, arch,
927 &kernel_size);
928
929 return Pack(filename, kernel_blob, kernel_size,
930 version, kernel_body_load_address,
931 signpriv_key);
932
933
934 case OPT_MODE_VERIFY:
935
936 /* Optional */
937
938 if (signpubkey_file) {
939 signpub_key = PublicKeyRead(signpubkey_file);
940 if (!signpub_key)
941 Fatal("Error reading public key.\n");
942 }
943
944 /* Do it */
945
946 kernel_blob = ReadOldBlobFromFileOrDie(filename, &kernel_size);
947
948 return Verify(kernel_blob, kernel_size, signpub_key,
949 keyblock_file, min_version);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700950 }
Bill Richardson72e344d2012-03-19 12:47:18 -0700951
952 fprintf(stderr, "You must specify a mode: --pack, --repack or --verify\n");
953 return PrintHelp(progname);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700954}