blob: 5fed77ac78b41bc519a3d92bdf17da42add247db [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>
Vincent Palatin56c85db2012-09-05 15:35:12 -07009#include <fcntl.h>
Randall Spangler7d6898d2010-06-11 09:22:13 -070010#include <getopt.h>
11#include <inttypes.h> /* For PRIu64 */
Vincent Palatin56c85db2012-09-05 15:35:12 -070012#include <sys/ioctl.h>
13#include <linux/fs.h> /* For BLKGETSIZE64 */
Bill Richardson249677d2010-06-23 11:16:37 -070014#include <stdarg.h>
Randall Spangler7d6898d2010-06-11 09:22:13 -070015#include <stddef.h>
16#include <stdio.h>
17#include <stdlib.h>
Bill Richardsona08b5c92010-06-30 21:59:43 -070018#include <string.h>
19#include <sys/stat.h>
20#include <sys/types.h>
Randall Spangler7d6898d2010-06-11 09:22:13 -070021#include <unistd.h>
22
23#include "cryptolib.h"
24#include "host_common.h"
25#include "kernel_blob.h"
Bill Richardson78299022014-06-20 14:33:00 -070026#include "util_misc.h"
Randall Spangler7d6898d2010-06-11 09:22:13 -070027#include "vboot_common.h"
28
Bill Richardson72e344d2012-03-19 12:47:18 -070029/* Global opts */
Bill Richardson249677d2010-06-23 11:16:37 -070030static int opt_debug = 0;
Bill Richardson72e344d2012-03-19 12:47:18 -070031static int opt_verbose = 0;
32static int opt_vblockonly = 0;
33static uint64_t opt_pad = 65536;
Bill Richardson249677d2010-06-23 11:16:37 -070034
35
Randall Spangler7d6898d2010-06-11 09:22:13 -070036/* Command line options */
37enum {
38 OPT_MODE_PACK = 1000,
Bill Richardsona08b5c92010-06-30 21:59:43 -070039 OPT_MODE_REPACK,
Randall Spangler7d6898d2010-06-11 09:22:13 -070040 OPT_MODE_VERIFY,
Che-Liang Chiou03762032011-02-22 11:16:51 +080041 OPT_ARCH,
Bill Richardsona08b5c92010-06-30 21:59:43 -070042 OPT_OLDBLOB,
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +080043 OPT_KLOADADDR,
Randall Spangler7d6898d2010-06-11 09:22:13 -070044 OPT_KEYBLOCK,
45 OPT_SIGNPUBKEY,
46 OPT_SIGNPRIVATE,
47 OPT_VERSION,
48 OPT_VMLINUZ,
49 OPT_BOOTLOADER,
50 OPT_CONFIG,
Bill Richardsona08b5c92010-06-30 21:59:43 -070051 OPT_VBLOCKONLY,
Randall Spangler7d6898d2010-06-11 09:22:13 -070052 OPT_PAD,
vbendebb2b0fcc2010-07-15 15:09:47 -070053 OPT_VERBOSE,
Randall Spanglerae87b922011-05-12 13:27:28 -070054 OPT_MINVERSION,
Randall Spangler7d6898d2010-06-11 09:22:13 -070055};
56
Bill Richardson72e344d2012-03-19 12:47:18 -070057typedef enum {
Che-Liang Chiou03762032011-02-22 11:16:51 +080058 ARCH_ARM,
Gaurav Shah36ba3402014-05-14 17:28:27 -070059 ARCH_X86, /* default */
60 ARCH_MIPS
Bill Richardson72e344d2012-03-19 12:47:18 -070061} arch_t;
Che-Liang Chiou03762032011-02-22 11:16:51 +080062
Randall Spangler7d6898d2010-06-11 09:22:13 -070063static struct option long_opts[] = {
64 {"pack", 1, 0, OPT_MODE_PACK },
Bill Richardsona08b5c92010-06-30 21:59:43 -070065 {"repack", 1, 0, OPT_MODE_REPACK },
Randall Spangler7d6898d2010-06-11 09:22:13 -070066 {"verify", 1, 0, OPT_MODE_VERIFY },
Che-Liang Chiou03762032011-02-22 11:16:51 +080067 {"arch", 1, 0, OPT_ARCH },
Bill Richardsona08b5c92010-06-30 21:59:43 -070068 {"oldblob", 1, 0, OPT_OLDBLOB },
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +080069 {"kloadaddr", 1, 0, OPT_KLOADADDR },
Randall Spangler7d6898d2010-06-11 09:22:13 -070070 {"keyblock", 1, 0, OPT_KEYBLOCK },
71 {"signpubkey", 1, 0, OPT_SIGNPUBKEY },
72 {"signprivate", 1, 0, OPT_SIGNPRIVATE },
73 {"version", 1, 0, OPT_VERSION },
Randall Spanglerae87b922011-05-12 13:27:28 -070074 {"minversion", 1, 0, OPT_MINVERSION },
Randall Spangler7d6898d2010-06-11 09:22:13 -070075 {"vmlinuz", 1, 0, OPT_VMLINUZ },
76 {"bootloader", 1, 0, OPT_BOOTLOADER },
77 {"config", 1, 0, OPT_CONFIG },
Bill Richardsona08b5c92010-06-30 21:59:43 -070078 {"vblockonly", 0, 0, OPT_VBLOCKONLY },
Randall Spangler7d6898d2010-06-11 09:22:13 -070079 {"pad", 1, 0, OPT_PAD },
Bill Richardson72e344d2012-03-19 12:47:18 -070080 {"verbose", 0, &opt_verbose, 1 },
Bill Richardson249677d2010-06-23 11:16:37 -070081 {"debug", 0, &opt_debug, 1 },
Randall Spangler7d6898d2010-06-11 09:22:13 -070082 {NULL, 0, 0, 0}
83};
84
85
86/* Print help and return error */
Bill Richardsona08b5c92010-06-30 21:59:43 -070087static int PrintHelp(char *progname) {
88 fprintf(stderr,
89 "This program creates, signs, and verifies the kernel blob\n");
90 fprintf(stderr,
91 "\n"
92 "Usage: %s --pack <file> [PARAMETERS]\n"
93 "\n"
94 " Required parameters:\n"
95 " --keyblock <file> Key block in .keyblock format\n"
Bill Richardson72e344d2012-03-19 12:47:18 -070096 " --signprivate <file> Private key to sign kernel data,\n"
97 " in .vbprivk format\n"
Bill Richardsona08b5c92010-06-30 21:59:43 -070098 " --version <number> Kernel version\n"
99 " --vmlinuz <file> Linux kernel bzImage file\n"
100 " --bootloader <file> Bootloader stub\n"
vbendebb2b0fcc2010-07-15 15:09:47 -0700101 " --config <file> Command line file\n"
Che-Liang Chiou03762032011-02-22 11:16:51 +0800102 " --arch <arch> Cpu architecture (default x86)\n"
Bill Richardsona08b5c92010-06-30 21:59:43 -0700103 "\n"
104 " Optional:\n"
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +0800105 " --kloadaddr <address> Assign kernel body load address\n"
Bill Richardsona08b5c92010-06-30 21:59:43 -0700106 " --pad <number> Verification padding size in bytes\n"
107 " --vblockonly Emit just the verification blob\n",
108 progname);
109 fprintf(stderr,
110 "\nOR\n\n"
111 "Usage: %s --repack <file> [PARAMETERS]\n"
112 "\n"
Bill Richardson72e344d2012-03-19 12:47:18 -0700113 " Required parameters:\n"
114 " --signprivate <file> Private key to sign kernel data,\n"
115 " in .vbprivk format\n"
Bill Richardsona08b5c92010-06-30 21:59:43 -0700116 " --oldblob <file> Previously packed kernel blob\n"
Bill Richardson72e344d2012-03-19 12:47:18 -0700117 " (including verfication blob)\n"
Bill Richardsona08b5c92010-06-30 21:59:43 -0700118 "\n"
119 " Optional:\n"
Bill Richardson72e344d2012-03-19 12:47:18 -0700120 " --keyblock <file> Key block in .keyblock format\n"
121 " --config <file> New command line file\n"
122 " --version <number> Kernel version\n"
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +0800123 " --kloadaddr <address> Assign kernel body load address\n"
Bill Richardson72e344d2012-03-19 12:47:18 -0700124 " --pad <number> Verification blob size in bytes\n"
Bill Richardsona08b5c92010-06-30 21:59:43 -0700125 " --vblockonly Emit just the verification blob\n",
126 progname);
127 fprintf(stderr,
128 "\nOR\n\n"
129 "Usage: %s --verify <file> [PARAMETERS]\n"
130 "\n"
vbendebb2b0fcc2010-07-15 15:09:47 -0700131 " Optional:\n"
Bill Richardson4f36ef32010-08-09 17:50:14 -0700132 " --signpubkey <file>"
Bill Richardson72e344d2012-03-19 12:47:18 -0700133 " Public key to verify kernel keyblock,\n"
134 " in .vbpubk format\n"
vbendebb2b0fcc2010-07-15 15:09:47 -0700135 " --verbose Print a more detailed report\n"
Bill Richardson72e344d2012-03-19 12:47:18 -0700136 " --keyblock <file> Outputs the verified key block,\n"
137 " in .keyblock format\n"
Randall Spangler7ecb39d2011-05-12 15:37:45 -0700138 " --pad <number> Verification padding size in bytes\n"
Randall Spanglerae87b922011-05-12 13:27:28 -0700139 " --minversion <number> Minimum combined kernel key version\n"
140 " and kernel version\n"
Bill Richardsona08b5c92010-06-30 21:59:43 -0700141 "\n",
142 progname);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700143 return 1;
144}
145
Bill Richardson249677d2010-06-23 11:16:37 -0700146static void Debug(const char *format, ...) {
147 if (!opt_debug)
148 return;
149
150 va_list ap;
151 va_start(ap, format);
152 fprintf(stderr, "DEBUG: ");
153 vfprintf(stderr, format, ap);
154 va_end(ap);
155}
156
Bill Richardson72e344d2012-03-19 12:47:18 -0700157static void Fatal(const char *format, ...) {
158 va_list ap;
159 va_start(ap, format);
160 fprintf(stderr, "ERROR: ");
161 vfprintf(stderr, format, ap);
162 va_end(ap);
163 exit(1);
164}
165
Bill Richardson2f6a71f2010-10-14 09:25:39 -0700166/* Return an explanation when fread() fails. */
167static const char *error_fread(FILE *fp) {
168 const char *retval = "beats me why";
169 if (feof(fp))
170 retval = "EOF";
171 else if (ferror(fp))
172 retval = strerror(errno);
173 clearerr(fp);
174 return retval;
175}
Randall Spangler7d6898d2010-06-11 09:22:13 -0700176
177/* Return the smallest integral multiple of [alignment] that is equal
178 * to or greater than [val]. Used to determine the number of
179 * pages/sectors/blocks/whatever needed to contain [val]
180 * items/bytes/etc. */
181static uint64_t roundup(uint64_t val, uint64_t alignment) {
182 uint64_t rem = val % alignment;
183 if ( rem )
184 return val + (alignment - rem);
185 return val;
186}
187
188
189/* Match regexp /\b--\b/ to delimit the start of the kernel commandline. If we
190 * don't find one, we'll use the whole thing. */
191static unsigned int find_cmdline_start(char *input, unsigned int max_len) {
192 int start = 0;
193 int i;
194 for(i = 0; i < max_len - 1 && input[i]; i++) {
195 if ('-' == input[i] && '-' == input[i + 1]) { /* found a "--" */
196 if ((i == 0 || ' ' == input[i - 1]) && /* nothing before it */
197 (i + 2 >= max_len || ' ' == input[i+2])) { /* nothing after it */
198 start = i+2; /* note: hope there's a trailing '\0' */
199 break;
200 }
201 }
202 }
203 while(' ' == input[start]) /* skip leading spaces */
204 start++;
205
206 return start;
207}
208
209
Bill Richardson72e344d2012-03-19 12:47:18 -0700210/****************************************************************************/
211/* Here are globals containing all the bits & pieces I'm working on. */
212
213/* The individual parts that go into the kernel blob */
214uint8_t *g_kernel_data;
215uint64_t g_kernel_size;
216uint8_t *g_param_data;
217uint64_t g_param_size;
218uint8_t *g_config_data;
219uint64_t g_config_size;
220uint8_t *g_bootloader_data;
221uint64_t g_bootloader_size;
222uint64_t g_bootloader_address;
Bill Richardsonc8b9ca62012-03-14 10:54:05 -0700223
224
Bill Richardson72e344d2012-03-19 12:47:18 -0700225/* The individual parts of the verification blob (including the data that
226 * immediately follows the headers) */
227VbKeyBlockHeader* g_keyblock;
228VbKernelPreambleHeader* g_preamble;
vbendebb2b0fcc2010-07-15 15:09:47 -0700229
Bill Richardson72e344d2012-03-19 12:47:18 -0700230/****************************************************************************/
Bill Richardsona08b5c92010-06-30 21:59:43 -0700231
vbendebb2b0fcc2010-07-15 15:09:47 -0700232/*
233 * Read the kernel command line from a file. Get rid of \n characters along
234 * the way and verify that the line fits into a 4K buffer.
235 *
236 * Return the buffer contaning the line on success (and set the line length
237 * using the passed in parameter), or NULL in case something goes wrong.
238 */
239static uint8_t* ReadConfigFile(const char* config_file, uint64_t* config_size)
240{
241 uint8_t* config_buf;
242 int ii;
243
244 config_buf = ReadFile(config_file, config_size);
245 Debug(" config file size=0x%" PRIx64 "\n", *config_size);
246 if (CROS_CONFIG_SIZE <= *config_size) { /* need room for trailing '\0' */
Randall Spangler32a65262011-06-27 10:49:11 -0700247 VbExError("Config file %s is too large (>= %d bytes)\n",
248 config_file, CROS_CONFIG_SIZE);
vbendebb2b0fcc2010-07-15 15:09:47 -0700249 return NULL;
250 }
251
252 /* Replace newlines with spaces */
253 for (ii = 0; ii < *config_size; ii++) {
254 if ('\n' == config_buf[ii]) {
255 config_buf[ii] = ' ';
256 }
257 }
258 return config_buf;
259}
260
Bill Richardson72e344d2012-03-19 12:47:18 -0700261
262/* Offset of kernel command line string from start of packed kernel blob */
263static uint64_t CmdLineOffset(VbKernelPreambleHeader *preamble) {
264 return preamble->bootloader_address - preamble->body_load_address -
265 CROS_CONFIG_SIZE - CROS_PARAMS_SIZE;
266}
267
268/* This initializes g_vmlinuz and g_param from a standard vmlinuz file.
269 * It returns 0 on error. */
270static int ImportVmlinuzFile(const char *vmlinuz_file, arch_t arch,
271 uint64_t kernel_body_load_address) {
272 uint8_t *kernel_buf;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700273 uint64_t kernel_size;
274 uint64_t kernel32_start = 0;
275 uint64_t kernel32_size = 0;
Kees Cooke0e4ed42013-04-10 18:05:51 -0700276 struct linux_kernel_params *params = NULL, *lh = NULL;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700277
278 /* Read the kernel */
Bill Richardson72e344d2012-03-19 12:47:18 -0700279 Debug("Reading %s\n", vmlinuz_file);
280 kernel_buf = ReadFile(vmlinuz_file, &kernel_size);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700281 if (!kernel_buf)
Bill Richardsona08b5c92010-06-30 21:59:43 -0700282 return 0;
Bill Richardson249677d2010-06-23 11:16:37 -0700283 Debug(" kernel file size=0x%" PRIx64 "\n", kernel_size);
Bill Richardson72e344d2012-03-19 12:47:18 -0700284 if (!kernel_size)
285 Fatal("Empty kernel file\n");
286
287 /* Go ahead and allocate the param region anyway. I don't think we need it
288 * for non-x86, but let's keep it for now. */
289 g_param_size = CROS_PARAMS_SIZE;
290 g_param_data= VbExMalloc(g_param_size);
291 Memset(g_param_data, 0, g_param_size);
292
293 /* Unless we're handling x86, the kernel is the kernel, so we're done. */
294 if (arch != ARCH_X86) {
295 g_kernel_data = kernel_buf;
296 g_kernel_size = kernel_size;
297 return 1;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700298 }
299
Bill Richardson72e344d2012-03-19 12:47:18 -0700300 /* The first part of the x86 vmlinuz is a header, followed by a real-mode
301 * boot stub. We only want the 32-bit part. */
Kees Cooke0e4ed42013-04-10 18:05:51 -0700302 lh = (struct linux_kernel_params *)kernel_buf;
Bill Richardson72e344d2012-03-19 12:47:18 -0700303 kernel32_start = (lh->setup_sects + 1) << 9;
304 if (kernel32_start >= kernel_size)
305 Fatal("Malformed kernel\n");
Randall Spangler7d6898d2010-06-11 09:22:13 -0700306 kernel32_size = kernel_size - kernel32_start;
Bill Richardson72e344d2012-03-19 12:47:18 -0700307
Bill Richardson249677d2010-06-23 11:16:37 -0700308 Debug(" kernel32_start=0x%" PRIx64 "\n", kernel32_start);
309 Debug(" kernel32_size=0x%" PRIx64 "\n", kernel32_size);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700310
Bill Richardson72e344d2012-03-19 12:47:18 -0700311 /* Keep just the 32-bit kernel. */
312 if (kernel32_size) {
313 g_kernel_size = kernel32_size;
314 g_kernel_data = VbExMalloc(g_kernel_size);
315 Memcpy(g_kernel_data, kernel_buf + kernel32_start, kernel32_size);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700316 }
Randall Spangler7d6898d2010-06-11 09:22:13 -0700317
Bill Richardson72e344d2012-03-19 12:47:18 -0700318 /* Copy the original zeropage data from kernel_buf into g_param_data, then
319 * tweak a few fields for our purposes */
320 params = (struct linux_kernel_params *)(g_param_data);
321 Memcpy(&(params->setup_sects), &(lh->setup_sects),
Kees Cooke0e4ed42013-04-10 18:05:51 -0700322 offsetof(struct linux_kernel_params, e820_entries)
323 - offsetof(struct linux_kernel_params, setup_sects));
Randall Spangler7d6898d2010-06-11 09:22:13 -0700324 params->boot_flag = 0;
Bill Richardson72e344d2012-03-19 12:47:18 -0700325 params->ramdisk_image = 0; /* we don't support initrd */
Randall Spangler7d6898d2010-06-11 09:22:13 -0700326 params->ramdisk_size = 0;
327 params->type_of_loader = 0xff;
Bill Richardson72e344d2012-03-19 12:47:18 -0700328 /* We need to point to the kernel commandline arg. On disk, it will come
329 * right after the 32-bit part of the kernel. */
330 params->cmd_line_ptr = kernel_body_load_address +
331 roundup(kernel32_size, CROS_ALIGN) +
332 find_cmdline_start((char *)g_config_data, g_config_size);
333 Debug(" cmdline_addr=0x%x\n", params->cmd_line_ptr);
Kees Cooke0e4ed42013-04-10 18:05:51 -0700334 Debug(" version=0x%x\n", params->version);
335 Debug(" kernel_alignment=0x%x\n", params->kernel_alignment);
336 Debug(" relocatable_kernel=0x%x\n", params->relocatable_kernel);
Che-Liang Chiou475bf442010-08-23 11:20:44 +0800337 /* A fake e820 memory map with 2 entries */
338 params->n_e820_entry = 2;
339 params->e820_entries[0].start_addr = 0x00000000;
340 params->e820_entries[0].segment_size = 0x00001000;
341 params->e820_entries[0].segment_type = E820_TYPE_RAM;
342 params->e820_entries[1].start_addr = 0xfffff000;
343 params->e820_entries[1].segment_size = 0x00001000;
344 params->e820_entries[1].segment_type = E820_TYPE_RESERVED;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700345
Bill Richardson72e344d2012-03-19 12:47:18 -0700346 /* done */
Randall Spangler32a65262011-06-27 10:49:11 -0700347 free(kernel_buf);
Bill Richardson72e344d2012-03-19 12:47:18 -0700348 return 1;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700349}
350
Bill Richardson72e344d2012-03-19 12:47:18 -0700351/* This returns just the kernel blob, with the verification blob separated
352 * and copied to new memory in g_keyblock and g_preamble. */
353static uint8_t* ReadOldBlobFromFileOrDie(const char *filename,
354 uint64_t* size_ptr) {
vbendebb2b0fcc2010-07-15 15:09:47 -0700355 FILE* fp = NULL;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700356 struct stat statbuf;
357 VbKeyBlockHeader* key_block;
358 VbKernelPreambleHeader* preamble;
359 uint64_t now = 0;
Bill Richardson72e344d2012-03-19 12:47:18 -0700360 uint8_t* buf;
361 uint8_t* kernel_blob_data;
362 uint64_t kernel_blob_size;
Vincent Palatin56c85db2012-09-05 15:35:12 -0700363 uint64_t file_size = 0;
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
Vincent Palatin56c85db2012-09-05 15:35:12 -0700368 if (S_ISBLK(statbuf.st_mode)) {
369 int fd;
370
371 if ((fd = open(filename, O_RDONLY)) >= 0) {
372 ioctl(fd, BLKGETSIZE64, &file_size);
373 close(fd);
374 }
375 } else {
376 file_size = statbuf.st_size;
377 }
378 Debug("%s size is 0x%" PRIx64 "\n", filename, file_size);
379 if (file_size < opt_pad)
Bill Richardson72e344d2012-03-19 12:47:18 -0700380 Fatal("%s is too small to be a valid kernel blob\n");
Bill Richardsona08b5c92010-06-30 21:59:43 -0700381
382 Debug("Reading %s\n", filename);
383 fp = fopen(filename, "rb");
Bill Richardson72e344d2012-03-19 12:47:18 -0700384 if (!fp)
385 Fatal("Unable to open file %s: %s\n", filename, strerror(errno));
Bill Richardsona08b5c92010-06-30 21:59:43 -0700386
Bill Richardson72e344d2012-03-19 12:47:18 -0700387 buf = VbExMalloc(opt_pad);
388 if (1 != fread(buf, opt_pad, 1, fp))
389 Fatal("Unable to read header from %s: %s\n", filename, error_fread(fp));
vbendebb2b0fcc2010-07-15 15:09:47 -0700390
Bill Richardson72e344d2012-03-19 12:47:18 -0700391 /* Sanity-check the key_block */
Bill Richardsona08b5c92010-06-30 21:59:43 -0700392 key_block = (VbKeyBlockHeader*)buf;
393 Debug("Keyblock is 0x%" PRIx64 " bytes\n", key_block->key_block_size);
394 now += key_block->key_block_size;
Vincent Palatin56c85db2012-09-05 15:35:12 -0700395 if (now > file_size)
Bill Richardson72e344d2012-03-19 12:47:18 -0700396 Fatal("key_block_size advances past the end of the blob\n");
397 if (now > opt_pad)
398 Fatal("key_block_size advances past %" PRIu64 " byte padding\n",
399 opt_pad);
400 /* LGTM */
401 g_keyblock = (VbKeyBlockHeader*)VbExMalloc(key_block->key_block_size);
402 Memcpy(g_keyblock, key_block, key_block->key_block_size);
Bill Richardsona08b5c92010-06-30 21:59:43 -0700403
Bill Richardson72e344d2012-03-19 12:47:18 -0700404 /* And the preamble */
Bill Richardsona08b5c92010-06-30 21:59:43 -0700405 preamble = (VbKernelPreambleHeader*)(buf + now);
406 Debug("Preamble is 0x%" PRIx64 " bytes\n", preamble->preamble_size);
407 now += preamble->preamble_size;
Vincent Palatin56c85db2012-09-05 15:35:12 -0700408 if (now > file_size)
Bill Richardson72e344d2012-03-19 12:47:18 -0700409 Fatal("preamble_size advances past the end of the blob\n");
410 if (now > opt_pad)
411 Fatal("preamble_size advances past %" PRIu64 " byte padding\n",
412 opt_pad);
413 /* LGTM */
414 Debug(" kernel_version = %d\n", preamble->kernel_version);
415 Debug(" bootloader_address = 0x%" PRIx64 "\n", preamble->bootloader_address);
416 Debug(" bootloader_size = 0x%" PRIx64 "\n", preamble->bootloader_size);
417 Debug(" kern_blob_size = 0x%" PRIx64 "\n",
418 preamble->body_signature.data_size);
419 g_preamble = (VbKernelPreambleHeader*)VbExMalloc(preamble->preamble_size);
420 Memcpy(g_preamble, preamble, preamble->preamble_size);
Bill Richardsona08b5c92010-06-30 21:59:43 -0700421
Bill Richardson72e344d2012-03-19 12:47:18 -0700422 /* Now for the kernel blob */
Bill Richardsona08b5c92010-06-30 21:59:43 -0700423 Debug("kernel blob is at offset 0x%" PRIx64 "\n", now);
Bill Richardson72e344d2012-03-19 12:47:18 -0700424 if (0 != fseek(fp, now, SEEK_SET))
425 Fatal("Unable to seek to 0x%" PRIx64 " in %s: %s\n", now, filename,
Bill Richardsona08b5c92010-06-30 21:59:43 -0700426 strerror(errno));
Bill Richardsona08b5c92010-06-30 21:59:43 -0700427
Bill Richardson72e344d2012-03-19 12:47:18 -0700428 /* Sanity check */
Vincent Palatin56c85db2012-09-05 15:35:12 -0700429 kernel_blob_size = file_size - now;
Bill Richardson72e344d2012-03-19 12:47:18 -0700430 if (!kernel_blob_size)
431 Fatal("No kernel blob found\n");
432 if (kernel_blob_size < preamble->body_signature.data_size)
433 fprintf(stderr, "Warning: kernel file only has 0x%" PRIx64 " bytes\n",
434 kernel_blob_size);
435 kernel_blob_data = VbExMalloc(kernel_blob_size);
Bill Richardsona08b5c92010-06-30 21:59:43 -0700436
Bill Richardson72e344d2012-03-19 12:47:18 -0700437 /* Read it in */
438 if (1 != fread(kernel_blob_data, kernel_blob_size, 1, fp))
439 Fatal("Unable to read kernel blob from %s: %s\n", filename,
Randall Spangler32a65262011-06-27 10:49:11 -0700440 error_fread(fp));
Bill Richardsona08b5c92010-06-30 21:59:43 -0700441
Bill Richardson72e344d2012-03-19 12:47:18 -0700442 /* Done */
443 VbExFree(buf);
Bill Richardsona08b5c92010-06-30 21:59:43 -0700444
Bill Richardson72e344d2012-03-19 12:47:18 -0700445 if (size_ptr)
446 *size_ptr = kernel_blob_size;
447
448 return kernel_blob_data;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700449}
450
451
Bill Richardson72e344d2012-03-19 12:47:18 -0700452/* Split a kernel blob into separate g_kernel, g_param, g_config, and
453 * g_bootloader parts. */
454static void UnpackKernelBlob(uint8_t *kernel_blob_data,
455 uint64_t kernel_blob_size) {
456
457 uint64_t k_blob_size = g_preamble->body_signature.data_size;
458 uint64_t k_blob_ofs = 0;
459 uint64_t b_size = g_preamble->bootloader_size;
460 uint64_t b_ofs = k_blob_ofs + g_preamble->bootloader_address -
461 g_preamble->body_load_address;
462 uint64_t p_ofs = b_ofs - CROS_CONFIG_SIZE;
463 uint64_t c_ofs = p_ofs - CROS_PARAMS_SIZE;
Bill Richardson72e344d2012-03-19 12:47:18 -0700464
465 Debug("k_blob_size = 0x%" PRIx64 "\n", k_blob_size );
466 Debug("k_blob_ofs = 0x%" PRIx64 "\n", k_blob_ofs );
467 Debug("b_size = 0x%" PRIx64 "\n", b_size );
468 Debug("b_ofs = 0x%" PRIx64 "\n", b_ofs );
469 Debug("p_ofs = 0x%" PRIx64 "\n", p_ofs );
470 Debug("c_ofs = 0x%" PRIx64 "\n", c_ofs );
471
472 g_kernel_size = c_ofs;
473 g_kernel_data = VbExMalloc(g_kernel_size);
474 Memcpy(g_kernel_data, kernel_blob_data, g_kernel_size);
475
476 g_param_size = CROS_PARAMS_SIZE;
477 g_param_data = VbExMalloc(g_param_size);
478 Memcpy(g_param_data, kernel_blob_data + p_ofs, g_param_size);
479
480 g_config_size = CROS_CONFIG_SIZE;
481 g_config_data = VbExMalloc(g_config_size);
482 Memcpy(g_config_data, kernel_blob_data + c_ofs, g_config_size);
483
484 g_bootloader_size = b_size;
485 g_bootloader_data = VbExMalloc(g_bootloader_size);
486 Memcpy(g_bootloader_data, kernel_blob_data + b_ofs, g_bootloader_size);
487}
488
489
490
491/****************************************************************************/
492
493static uint8_t* CreateKernelBlob(uint64_t kernel_body_load_address,
494 arch_t arch,
495 uint64_t *size_ptr) {
496 uint8_t *kern_blob;
497 uint64_t kern_blob_size;
498 uint64_t now;
499 uint64_t bootloader_size = roundup(g_bootloader_size, CROS_ALIGN);
500
501 /* Put the kernel blob together */
502 kern_blob_size = roundup(g_kernel_size, CROS_ALIGN) +
503 CROS_CONFIG_SIZE + CROS_PARAMS_SIZE + bootloader_size;
504 Debug("kern_blob_size=0x%" PRIx64 "\n", kern_blob_size);
505 kern_blob = VbExMalloc(kern_blob_size);
506 Memset(kern_blob, 0, kern_blob_size);
507 now = 0;
508
509 Debug("kernel goes at kern_blob+0x%" PRIx64 "\n", now);
510
511 Memcpy(kern_blob+now, g_kernel_data, g_kernel_size);
512 now += roundup(g_kernel_size, CROS_ALIGN);
513
514 Debug("config goes at kern_blob+0x%" PRIx64 "\n", now);
515 if (g_config_size)
516 Memcpy(kern_blob + now, g_config_data, g_config_size);
517 now += CROS_CONFIG_SIZE;
518
519 Debug("params goes at kern_blob+0x%" PRIx64 "\n", now);
520 if (g_param_size) {
521 Memcpy(kern_blob + now, g_param_data, g_param_size);
522 }
523 now += CROS_PARAMS_SIZE;
524
525 Debug("bootloader goes at kern_blob+0x%" PRIx64 "\n", now);
526 g_bootloader_address = kernel_body_load_address + now;
527 Debug(" bootloader_address=0x%" PRIx64 "\n", g_bootloader_address);
528 Debug(" bootloader_size=0x%" PRIx64 "\n", bootloader_size);
529 if (bootloader_size)
530 Memcpy(kern_blob + now, g_bootloader_data, g_bootloader_size);
531 now += bootloader_size;
532 Debug("end of kern_blob at kern_blob+0x%" PRIx64 "\n", now);
533
534 /* Done */
535 if (size_ptr)
536 *size_ptr = kern_blob_size;
537
538 return kern_blob;
539}
540
541static int Pack(const char* outfile,
542 uint8_t *kernel_blob,
543 uint64_t kernel_size,
544 int version,
545 uint64_t kernel_body_load_address,
546 VbPrivateKey* signpriv_key) {
Bill Richardsona08b5c92010-06-30 21:59:43 -0700547 VbSignature* body_sig;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700548 FILE* f;
549 uint64_t i;
Bill Richardsonc8b9ca62012-03-14 10:54:05 -0700550 uint64_t written = 0;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700551
Randall Spangler7d6898d2010-06-11 09:22:13 -0700552 /* Sign the kernel data */
Bill Richardson72e344d2012-03-19 12:47:18 -0700553 body_sig = CalculateSignature(kernel_blob, kernel_size, signpriv_key);
554 if (!body_sig)
555 Fatal("Error calculating body signature\n");
Randall Spangler7d6898d2010-06-11 09:22:13 -0700556
557 /* Create preamble */
Bill Richardson72e344d2012-03-19 12:47:18 -0700558 g_preamble = CreateKernelPreamble(version,
559 kernel_body_load_address,
560 g_bootloader_address,
561 roundup(g_bootloader_size, CROS_ALIGN),
562 body_sig,
563 opt_pad - g_keyblock->key_block_size,
564 signpriv_key);
565 if (!g_preamble) {
Randall Spangler32a65262011-06-27 10:49:11 -0700566 VbExError("Error creating preamble.\n");
Randall Spangler7d6898d2010-06-11 09:22:13 -0700567 return 1;
568 }
Randall Spangler7d6898d2010-06-11 09:22:13 -0700569 /* Write the output file */
Bill Richardson249677d2010-06-23 11:16:37 -0700570 Debug("writing %s...\n", outfile);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700571 f = fopen(outfile, "wb");
572 if (!f) {
Randall Spangler32a65262011-06-27 10:49:11 -0700573 VbExError("Can't open output file %s\n", outfile);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700574 return 1;
575 }
Bill Richardson72e344d2012-03-19 12:47:18 -0700576 Debug("0x%" PRIx64 " bytes of key_block\n", g_keyblock->key_block_size);
577 Debug("0x%" PRIx64 " bytes of preamble\n", g_preamble->preamble_size);
578 i = ((1 != fwrite(g_keyblock, g_keyblock->key_block_size, 1, f)) ||
579 (1 != fwrite(g_preamble, g_preamble->preamble_size, 1, f)));
Randall Spangler7d6898d2010-06-11 09:22:13 -0700580 if (i) {
Randall Spangler32a65262011-06-27 10:49:11 -0700581 VbExError("Can't write output file %s\n", outfile);
Bill Richardsona08b5c92010-06-30 21:59:43 -0700582 fclose(f);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700583 unlink(outfile);
584 return 1;
585 }
Bill Richardson72e344d2012-03-19 12:47:18 -0700586 written += g_keyblock->key_block_size;
587 written += g_preamble->preamble_size;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700588
Bill Richardson72e344d2012-03-19 12:47:18 -0700589 if (!opt_vblockonly) {
590 Debug("0x%" PRIx64 " bytes of kern_blob\n", kernel_size);
591 i = (1 != fwrite(kernel_blob, kernel_size, 1, f));
Bill Richardsona08b5c92010-06-30 21:59:43 -0700592 if (i) {
Bill Richardsona08b5c92010-06-30 21:59:43 -0700593 fclose(f);
594 unlink(outfile);
Bill Richardson72e344d2012-03-19 12:47:18 -0700595 Fatal("Can't write output file %s\n", outfile);
Bill Richardsona08b5c92010-06-30 21:59:43 -0700596 }
Bill Richardson72e344d2012-03-19 12:47:18 -0700597 written += kernel_size;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700598 }
Bill Richardsonc8b9ca62012-03-14 10:54:05 -0700599 Debug("0x%" PRIx64 " bytes total\n", written);
Bill Richardsona08b5c92010-06-30 21:59:43 -0700600 fclose(f);
601
Randall Spangler7d6898d2010-06-11 09:22:13 -0700602 /* Success */
603 return 0;
604}
605
Bill Richardson72e344d2012-03-19 12:47:18 -0700606static int Verify(uint8_t* kernel_blob,
607 uint64_t kernel_size,
608 VbPublicKey* signpub_key,
609 const char* keyblock_outfile,
610 uint64_t min_version) {
Randall Spangler7d6898d2010-06-11 09:22:13 -0700611 VbPublicKey* data_key;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700612 RSAPublicKey* rsa;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700613
Bill Richardson72e344d2012-03-19 12:47:18 -0700614 if (0 != KeyBlockVerify(g_keyblock, g_keyblock->key_block_size,
615 signpub_key, (0 == signpub_key)))
616 Fatal("Error verifying key block.\n");
Will Drewry9342f882010-10-26 10:22:05 -0500617
Randall Spangler7d6898d2010-06-11 09:22:13 -0700618 printf("Key block:\n");
Bill Richardson72e344d2012-03-19 12:47:18 -0700619 data_key = &g_keyblock->data_key;
620 if (opt_verbose)
621 printf(" Signature: %s\n", signpub_key ? "valid" : "ignored");
622 printf(" Size: 0x%" PRIx64 "\n", g_keyblock->key_block_size);
623 printf(" Flags: %" PRIu64 " ", g_keyblock->key_block_flags);
624 if (g_keyblock->key_block_flags & KEY_BLOCK_FLAG_DEVELOPER_0)
Bill Richardson60bcbe32010-09-09 14:53:56 -0700625 printf(" !DEV");
Bill Richardson72e344d2012-03-19 12:47:18 -0700626 if (g_keyblock->key_block_flags & KEY_BLOCK_FLAG_DEVELOPER_1)
Bill Richardson60bcbe32010-09-09 14:53:56 -0700627 printf(" DEV");
Bill Richardson72e344d2012-03-19 12:47:18 -0700628 if (g_keyblock->key_block_flags & KEY_BLOCK_FLAG_RECOVERY_0)
Bill Richardson60bcbe32010-09-09 14:53:56 -0700629 printf(" !REC");
Bill Richardson72e344d2012-03-19 12:47:18 -0700630 if (g_keyblock->key_block_flags & KEY_BLOCK_FLAG_RECOVERY_1)
Bill Richardson60bcbe32010-09-09 14:53:56 -0700631 printf(" REC");
632 printf("\n");
Randall Spangler7d6898d2010-06-11 09:22:13 -0700633 printf(" Data key algorithm: %" PRIu64 " %s\n", data_key->algorithm,
634 (data_key->algorithm < kNumAlgorithms ?
635 algo_strings[data_key->algorithm] : "(invalid)"));
636 printf(" Data key version: %" PRIu64 "\n", data_key->key_version);
Bill Richardson60bcbe32010-09-09 14:53:56 -0700637 printf(" Data key sha1sum: ");
638 PrintPubKeySha1Sum(data_key);
639 printf("\n");
Randall Spangler7d6898d2010-06-11 09:22:13 -0700640
Bill Richardson72e344d2012-03-19 12:47:18 -0700641 if (keyblock_outfile) {
642 FILE* f = NULL;
643 f = fopen(keyblock_outfile, "wb");
644 if (!f)
645 Fatal("Can't open key block file %s\n", keyblock_outfile);
646 if (1 != fwrite(g_keyblock, g_keyblock->key_block_size, 1, f))
647 Fatal("Can't write key block file %s\n", keyblock_outfile);
648 fclose(f);
649 }
650
651 if (data_key->key_version < (min_version >> 16))
652 Fatal("Data key version %" PRIu64
Randall Spangler32a65262011-06-27 10:49:11 -0700653 " is lower than minimum %" PRIu64".\n",
654 data_key->key_version, (min_version >> 16));
Randall Spanglerae87b922011-05-12 13:27:28 -0700655
Bill Richardson72e344d2012-03-19 12:47:18 -0700656 rsa = PublicKeyToRSA(data_key);
657 if (!rsa)
658 Fatal("Error parsing data key.\n");
Randall Spangler7d6898d2010-06-11 09:22:13 -0700659
660 /* Verify preamble */
Bill Richardson72e344d2012-03-19 12:47:18 -0700661 if (0 != VerifyKernelPreamble(
662 g_preamble, g_preamble->preamble_size, rsa))
663 Fatal("Error verifying preamble.\n");
Randall Spangler7d6898d2010-06-11 09:22:13 -0700664
665 printf("Preamble:\n");
Bill Richardson72e344d2012-03-19 12:47:18 -0700666 printf(" Size: 0x%" PRIx64 "\n", g_preamble->preamble_size);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700667 printf(" Header version: %" PRIu32 ".%" PRIu32"\n",
Bill Richardson72e344d2012-03-19 12:47:18 -0700668 g_preamble->header_version_major, g_preamble->header_version_minor);
669 printf(" Kernel version: %" PRIu64 "\n", g_preamble->kernel_version);
670 printf(" Body load address: 0x%" PRIx64 "\n",
671 g_preamble->body_load_address);
Bill Richardson249677d2010-06-23 11:16:37 -0700672 printf(" Body size: 0x%" PRIx64 "\n",
Bill Richardson72e344d2012-03-19 12:47:18 -0700673 g_preamble->body_signature.data_size);
Randall Spangler87c13d82010-07-19 10:35:40 -0700674 printf(" Bootloader address: 0x%" PRIx64 "\n",
Bill Richardson72e344d2012-03-19 12:47:18 -0700675 g_preamble->bootloader_address);
676 printf(" Bootloader size: 0x%" PRIx64 "\n",
677 g_preamble->bootloader_size);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700678
Bill Richardson72e344d2012-03-19 12:47:18 -0700679 if (g_preamble->kernel_version < (min_version & 0xFFFF))
680 Fatal("Kernel version %" PRIu64 " is lower than minimum %" PRIu64 ".\n",
681 g_preamble->kernel_version, (min_version & 0xFFFF));
Randall Spanglerae87b922011-05-12 13:27:28 -0700682
Randall Spangler7d6898d2010-06-11 09:22:13 -0700683 /* Verify body */
Bill Richardson72e344d2012-03-19 12:47:18 -0700684 if (0 != VerifyData(kernel_blob, kernel_size,
685 &g_preamble->body_signature, rsa))
686 Fatal("Error verifying kernel body.\n");
Randall Spangler7d6898d2010-06-11 09:22:13 -0700687 printf("Body verification succeeded.\n");
vbendebb2b0fcc2010-07-15 15:09:47 -0700688
vbendebb2b0fcc2010-07-15 15:09:47 -0700689
Bill Richardson72e344d2012-03-19 12:47:18 -0700690 if (opt_verbose)
691 printf("Config:\n%s\n", kernel_blob + CmdLineOffset(g_preamble));
vbendebb2b0fcc2010-07-15 15:09:47 -0700692
Bill Richardson72e344d2012-03-19 12:47:18 -0700693 return 0;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700694}
695
Bill Richardson72e344d2012-03-19 12:47:18 -0700696/****************************************************************************/
Randall Spangler7d6898d2010-06-11 09:22:13 -0700697
698int main(int argc, char* argv[]) {
Randall Spangler7d6898d2010-06-11 09:22:13 -0700699 char* filename = NULL;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700700 char* oldfile = NULL;
Bill Richardson72e344d2012-03-19 12:47:18 -0700701 char* keyblock_file = NULL;
702 char* signpubkey_file = NULL;
703 char* signprivkey_file = NULL;
704 char* version_str = NULL;
vbendeb00b90882010-10-21 13:46:16 -0700705 int version = -1;
Bill Richardson72e344d2012-03-19 12:47:18 -0700706 char* vmlinuz_file = NULL;
707 char* bootloader_file = NULL;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700708 char* config_file = NULL;
Bill Richardson72e344d2012-03-19 12:47:18 -0700709 arch_t arch = ARCH_X86;
710 char *address_str = NULL;
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +0800711 uint64_t kernel_body_load_address = CROS_32BIT_ENTRY_ADDR;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700712 int mode = 0;
713 int parse_error = 0;
Randall Spanglerae87b922011-05-12 13:27:28 -0700714 uint64_t min_version = 0;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700715 char* e;
Bill Richardson72e344d2012-03-19 12:47:18 -0700716 int i;
717 VbPrivateKey* signpriv_key = NULL;
718 VbPublicKey* signpub_key = NULL;
719 uint8_t* kernel_blob = NULL;
720 uint64_t kernel_size = 0;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700721
722 char *progname = strrchr(argv[0], '/');
723 if (progname)
724 progname++;
725 else
726 progname = argv[0];
727
vbendebb2b0fcc2010-07-15 15:09:47 -0700728 while (((i = getopt_long(argc, argv, ":", long_opts, NULL)) != -1) &&
729 !parse_error) {
Randall Spangler7d6898d2010-06-11 09:22:13 -0700730 switch (i) {
Bill Richardson72e344d2012-03-19 12:47:18 -0700731 default:
732 case '?':
733 /* Unhandled option */
734 parse_error = 1;
735 break;
736
737 case 0:
738 /* silently handled option */
739 break;
740
741 case OPT_MODE_PACK:
742 case OPT_MODE_REPACK:
743 case OPT_MODE_VERIFY:
744 if (mode && (mode != i)) {
745 fprintf(stderr, "Only a single mode can be specified\n");
Randall Spangler7d6898d2010-06-11 09:22:13 -0700746 parse_error = 1;
747 break;
Bill Richardson72e344d2012-03-19 12:47:18 -0700748 }
749 mode = i;
750 filename = optarg;
751 break;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700752
Bill Richardson72e344d2012-03-19 12:47:18 -0700753 case OPT_ARCH:
754 /* check the first 3 characters to also detect x86_64 */
755 if ((!strncasecmp(optarg, "x86", 3)) ||
756 (!strcasecmp(optarg, "amd64")))
757 arch = ARCH_X86;
758 else if (!strcasecmp(optarg, "arm"))
759 arch = ARCH_ARM;
Gaurav Shah36ba3402014-05-14 17:28:27 -0700760 else if (!strcasecmp(optarg, "mips"))
761 arch = ARCH_MIPS;
Bill Richardson72e344d2012-03-19 12:47:18 -0700762 else {
763 fprintf(stderr, "Unknown architecture string: %s\n", optarg);
764 parse_error = 1;
765 }
766 break;
Bill Richardson4f36ef32010-08-09 17:50:14 -0700767
Bill Richardson72e344d2012-03-19 12:47:18 -0700768 case OPT_OLDBLOB:
769 oldfile = optarg;
770 break;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700771
Bill Richardson72e344d2012-03-19 12:47:18 -0700772 case OPT_KLOADADDR:
773 address_str = optarg;
774 kernel_body_load_address = strtoul(optarg, &e, 0);
775 if (!*optarg || (e && *e)) {
776 fprintf(stderr, "Invalid --kloadaddr\n");
777 parse_error = 1;
778 }
779 break;
Che-Liang Chiou03762032011-02-22 11:16:51 +0800780
Bill Richardson72e344d2012-03-19 12:47:18 -0700781 case OPT_KEYBLOCK:
782 keyblock_file = optarg;
783 break;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700784
Bill Richardson72e344d2012-03-19 12:47:18 -0700785 case OPT_SIGNPUBKEY:
786 signpubkey_file = optarg;
787 break;
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +0800788
Bill Richardson72e344d2012-03-19 12:47:18 -0700789 case OPT_SIGNPRIVATE:
790 signprivkey_file = optarg;
791 break;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700792
Bill Richardson72e344d2012-03-19 12:47:18 -0700793 case OPT_VMLINUZ:
794 vmlinuz_file = optarg;
795 break;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700796
Bill Richardson72e344d2012-03-19 12:47:18 -0700797 case OPT_BOOTLOADER:
798 bootloader_file = optarg;
799 break;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700800
Bill Richardson72e344d2012-03-19 12:47:18 -0700801 case OPT_CONFIG:
802 config_file = optarg;
803 break;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700804
Bill Richardson72e344d2012-03-19 12:47:18 -0700805 case OPT_VBLOCKONLY:
806 opt_vblockonly = 1;
807 break;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700808
Bill Richardson72e344d2012-03-19 12:47:18 -0700809 case OPT_VERSION:
810 version_str = optarg;
811 version = strtoul(optarg, &e, 0);
812 if (!*optarg || (e && *e)) {
813 fprintf(stderr, "Invalid --version\n");
814 parse_error = 1;
815 }
816 break;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700817
Bill Richardson72e344d2012-03-19 12:47:18 -0700818 case OPT_MINVERSION:
819 min_version = strtoul(optarg, &e, 0);
820 if (!*optarg || (e && *e)) {
821 fprintf(stderr, "Invalid --minversion\n");
822 parse_error = 1;
823 }
824 break;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700825
Bill Richardson72e344d2012-03-19 12:47:18 -0700826 case OPT_PAD:
827 opt_pad = strtoul(optarg, &e, 0);
828 if (!*optarg || (e && *e)) {
829 fprintf(stderr, "Invalid --pad\n");
830 parse_error = 1;
831 }
832 break;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700833 }
834 }
835
836 if (parse_error)
Bill Richardsona08b5c92010-06-30 21:59:43 -0700837 return PrintHelp(progname);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700838
839 switch(mode) {
Bill Richardson72e344d2012-03-19 12:47:18 -0700840 case OPT_MODE_PACK:
Bill Richardsona08b5c92010-06-30 21:59:43 -0700841
Bill Richardson72e344d2012-03-19 12:47:18 -0700842 /* Required */
vbendebb2b0fcc2010-07-15 15:09:47 -0700843
Bill Richardson72e344d2012-03-19 12:47:18 -0700844 if (!keyblock_file)
845 Fatal("Missing required keyblock file.\n");
Bill Richardsona08b5c92010-06-30 21:59:43 -0700846
Bill Richardson72e344d2012-03-19 12:47:18 -0700847 g_keyblock = (VbKeyBlockHeader*)ReadFile(keyblock_file, 0);
848 if (!g_keyblock)
849 Fatal("Error reading key block.\n");
Bill Richardsona08b5c92010-06-30 21:59:43 -0700850
Bill Richardson72e344d2012-03-19 12:47:18 -0700851 if (!signprivkey_file)
852 Fatal("Missing required signprivate file.\n");
853
854 signpriv_key = PrivateKeyRead(signprivkey_file);
855 if (!signpriv_key)
856 Fatal("Error reading signing key.\n");
857
858 /* Optional */
859
860 if (config_file) {
861 Debug("Reading %s\n", config_file);
862 g_config_data = ReadConfigFile(config_file, &g_config_size);
Lucian Cojocar2312ab62012-07-30 15:21:49 -0700863 if (!g_config_data)
864 Fatal("Error reading config file.\n");
Bill Richardson72e344d2012-03-19 12:47:18 -0700865 }
866
867 if (vmlinuz_file)
868 if (!ImportVmlinuzFile(vmlinuz_file, arch, kernel_body_load_address))
869 Fatal("Error reading kernel file.\n");
870
871 if (bootloader_file) {
872 Debug("Reading %s\n", bootloader_file);
873 g_bootloader_data = ReadFile(bootloader_file, &g_bootloader_size);
874 if (!g_bootloader_data)
875 Fatal("Error reading bootloader file.\n");
876 Debug(" bootloader file size=0x%" PRIx64 "\n", g_bootloader_size);
877 }
878
879 /* Do it */
880
881 kernel_blob = CreateKernelBlob(kernel_body_load_address, arch,
882 &kernel_size);
883
884 return Pack(filename, kernel_blob, kernel_size,
885 version, kernel_body_load_address,
886 signpriv_key);
887
888 case OPT_MODE_REPACK:
889
890 /* Required */
891
892 if (!signprivkey_file)
893 Fatal("Missing required signprivate file.\n");
894
895 signpriv_key = PrivateKeyRead(signprivkey_file);
896 if (!signpriv_key)
897 Fatal("Error reading signing key.\n");
898
899 if (!oldfile)
900 Fatal("Missing previously packed blob.\n");
901
902 /* Load the old blob */
903
904 kernel_blob = ReadOldBlobFromFileOrDie(oldfile, &kernel_size);
905 if (0 != Verify(kernel_blob, kernel_size, 0, 0, 0))
906 Fatal("The oldblob doesn't verify\n");
907
908 /* Take it apart */
909
910 UnpackKernelBlob(kernel_blob, kernel_size);
911 free(kernel_blob);
912
913 /* Load optional params */
914
915 if (!version_str)
916 version = g_preamble->kernel_version;
917
918 if (!address_str)
919 kernel_body_load_address = g_preamble->body_load_address;
920
921 if (config_file) {
922 if (g_config_data)
923 free(g_config_data);
924 Debug("Reading %s\n", config_file);
925 g_config_data = ReadConfigFile(config_file, &g_config_size);
Lucian Cojocar2312ab62012-07-30 15:21:49 -0700926 if (!g_config_data)
927 Fatal("Error reading config file.\n");
Bill Richardson72e344d2012-03-19 12:47:18 -0700928 }
929
930 if (keyblock_file) {
931 if (g_keyblock)
932 free(g_keyblock);
933 g_keyblock = (VbKeyBlockHeader*)ReadFile(keyblock_file, 0);
934 if (!g_keyblock)
935 Fatal("Error reading key block.\n");
936 }
937
938 /* Put it back together */
939
940 kernel_blob = CreateKernelBlob(kernel_body_load_address, arch,
941 &kernel_size);
942
943 return Pack(filename, kernel_blob, kernel_size,
944 version, kernel_body_load_address,
945 signpriv_key);
946
947
948 case OPT_MODE_VERIFY:
949
950 /* Optional */
951
952 if (signpubkey_file) {
953 signpub_key = PublicKeyRead(signpubkey_file);
954 if (!signpub_key)
955 Fatal("Error reading public key.\n");
956 }
957
958 /* Do it */
959
960 kernel_blob = ReadOldBlobFromFileOrDie(filename, &kernel_size);
961
962 return Verify(kernel_blob, kernel_size, signpub_key,
963 keyblock_file, min_version);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700964 }
Bill Richardson72e344d2012-03-19 12:47:18 -0700965
966 fprintf(stderr, "You must specify a mode: --pack, --repack or --verify\n");
967 return PrintHelp(progname);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700968}