blob: 820b3af49a9b4c5a1fce5e9007117e604dc0fdc5 [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"
26#include "vboot_common.h"
27
Bill Richardson72e344d2012-03-19 12:47:18 -070028/* Global opts */
Bill Richardson249677d2010-06-23 11:16:37 -070029static int opt_debug = 0;
Bill Richardson72e344d2012-03-19 12:47:18 -070030static int opt_verbose = 0;
31static int opt_vblockonly = 0;
32static uint64_t opt_pad = 65536;
Bill Richardson249677d2010-06-23 11:16:37 -070033
34
Randall Spangler7d6898d2010-06-11 09:22:13 -070035/* Command line options */
36enum {
37 OPT_MODE_PACK = 1000,
Bill Richardsona08b5c92010-06-30 21:59:43 -070038 OPT_MODE_REPACK,
Randall Spangler7d6898d2010-06-11 09:22:13 -070039 OPT_MODE_VERIFY,
Che-Liang Chiou03762032011-02-22 11:16:51 +080040 OPT_ARCH,
Bill Richardsona08b5c92010-06-30 21:59:43 -070041 OPT_OLDBLOB,
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +080042 OPT_KLOADADDR,
Randall Spangler7d6898d2010-06-11 09:22:13 -070043 OPT_KEYBLOCK,
44 OPT_SIGNPUBKEY,
45 OPT_SIGNPRIVATE,
46 OPT_VERSION,
47 OPT_VMLINUZ,
48 OPT_BOOTLOADER,
49 OPT_CONFIG,
Bill Richardsona08b5c92010-06-30 21:59:43 -070050 OPT_VBLOCKONLY,
Randall Spangler7d6898d2010-06-11 09:22:13 -070051 OPT_PAD,
vbendebb2b0fcc2010-07-15 15:09:47 -070052 OPT_VERBOSE,
Randall Spanglerae87b922011-05-12 13:27:28 -070053 OPT_MINVERSION,
Randall Spangler7d6898d2010-06-11 09:22:13 -070054};
55
Bill Richardson72e344d2012-03-19 12:47:18 -070056typedef enum {
Che-Liang Chiou03762032011-02-22 11:16:51 +080057 ARCH_ARM,
58 ARCH_X86 /* default */
Bill Richardson72e344d2012-03-19 12:47:18 -070059} arch_t;
Che-Liang Chiou03762032011-02-22 11:16:51 +080060
Randall Spangler7d6898d2010-06-11 09:22:13 -070061static struct option long_opts[] = {
62 {"pack", 1, 0, OPT_MODE_PACK },
Bill Richardsona08b5c92010-06-30 21:59:43 -070063 {"repack", 1, 0, OPT_MODE_REPACK },
Randall Spangler7d6898d2010-06-11 09:22:13 -070064 {"verify", 1, 0, OPT_MODE_VERIFY },
Che-Liang Chiou03762032011-02-22 11:16:51 +080065 {"arch", 1, 0, OPT_ARCH },
Bill Richardsona08b5c92010-06-30 21:59:43 -070066 {"oldblob", 1, 0, OPT_OLDBLOB },
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +080067 {"kloadaddr", 1, 0, OPT_KLOADADDR },
Randall Spangler7d6898d2010-06-11 09:22:13 -070068 {"keyblock", 1, 0, OPT_KEYBLOCK },
69 {"signpubkey", 1, 0, OPT_SIGNPUBKEY },
70 {"signprivate", 1, 0, OPT_SIGNPRIVATE },
71 {"version", 1, 0, OPT_VERSION },
Randall Spanglerae87b922011-05-12 13:27:28 -070072 {"minversion", 1, 0, OPT_MINVERSION },
Randall Spangler7d6898d2010-06-11 09:22:13 -070073 {"vmlinuz", 1, 0, OPT_VMLINUZ },
74 {"bootloader", 1, 0, OPT_BOOTLOADER },
75 {"config", 1, 0, OPT_CONFIG },
Bill Richardsona08b5c92010-06-30 21:59:43 -070076 {"vblockonly", 0, 0, OPT_VBLOCKONLY },
Randall Spangler7d6898d2010-06-11 09:22:13 -070077 {"pad", 1, 0, OPT_PAD },
Bill Richardson72e344d2012-03-19 12:47:18 -070078 {"verbose", 0, &opt_verbose, 1 },
Bill Richardson249677d2010-06-23 11:16:37 -070079 {"debug", 0, &opt_debug, 1 },
Randall Spangler7d6898d2010-06-11 09:22:13 -070080 {NULL, 0, 0, 0}
81};
82
83
84/* Print help and return error */
Bill Richardsona08b5c92010-06-30 21:59:43 -070085static int PrintHelp(char *progname) {
86 fprintf(stderr,
87 "This program creates, signs, and verifies the kernel blob\n");
88 fprintf(stderr,
89 "\n"
90 "Usage: %s --pack <file> [PARAMETERS]\n"
91 "\n"
92 " Required parameters:\n"
93 " --keyblock <file> Key block in .keyblock format\n"
Bill Richardson72e344d2012-03-19 12:47:18 -070094 " --signprivate <file> Private key to sign kernel data,\n"
95 " in .vbprivk format\n"
Bill Richardsona08b5c92010-06-30 21:59:43 -070096 " --version <number> Kernel version\n"
97 " --vmlinuz <file> Linux kernel bzImage file\n"
98 " --bootloader <file> Bootloader stub\n"
vbendebb2b0fcc2010-07-15 15:09:47 -070099 " --config <file> Command line file\n"
Che-Liang Chiou03762032011-02-22 11:16:51 +0800100 " --arch <arch> Cpu architecture (default x86)\n"
Bill Richardsona08b5c92010-06-30 21:59:43 -0700101 "\n"
102 " Optional:\n"
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +0800103 " --kloadaddr <address> Assign kernel body load address\n"
Bill Richardsona08b5c92010-06-30 21:59:43 -0700104 " --pad <number> Verification padding size in bytes\n"
105 " --vblockonly Emit just the verification blob\n",
106 progname);
107 fprintf(stderr,
108 "\nOR\n\n"
109 "Usage: %s --repack <file> [PARAMETERS]\n"
110 "\n"
Bill Richardson72e344d2012-03-19 12:47:18 -0700111 " Required parameters:\n"
112 " --signprivate <file> Private key to sign kernel data,\n"
113 " in .vbprivk format\n"
Bill Richardsona08b5c92010-06-30 21:59:43 -0700114 " --oldblob <file> Previously packed kernel blob\n"
Bill Richardson72e344d2012-03-19 12:47:18 -0700115 " (including verfication blob)\n"
Bill Richardsona08b5c92010-06-30 21:59:43 -0700116 "\n"
117 " Optional:\n"
Bill Richardson72e344d2012-03-19 12:47:18 -0700118 " --keyblock <file> Key block in .keyblock format\n"
119 " --config <file> New command line file\n"
120 " --version <number> Kernel version\n"
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +0800121 " --kloadaddr <address> Assign kernel body load address\n"
Bill Richardson72e344d2012-03-19 12:47:18 -0700122 " --pad <number> Verification blob size in bytes\n"
Bill Richardsona08b5c92010-06-30 21:59:43 -0700123 " --vblockonly Emit just the verification blob\n",
124 progname);
125 fprintf(stderr,
126 "\nOR\n\n"
127 "Usage: %s --verify <file> [PARAMETERS]\n"
128 "\n"
vbendebb2b0fcc2010-07-15 15:09:47 -0700129 " Optional:\n"
Bill Richardson4f36ef32010-08-09 17:50:14 -0700130 " --signpubkey <file>"
Bill Richardson72e344d2012-03-19 12:47:18 -0700131 " Public key to verify kernel keyblock,\n"
132 " in .vbpubk format\n"
vbendebb2b0fcc2010-07-15 15:09:47 -0700133 " --verbose Print a more detailed report\n"
Bill Richardson72e344d2012-03-19 12:47:18 -0700134 " --keyblock <file> Outputs the verified key block,\n"
135 " in .keyblock format\n"
Randall Spangler7ecb39d2011-05-12 15:37:45 -0700136 " --pad <number> Verification padding size in bytes\n"
Randall Spanglerae87b922011-05-12 13:27:28 -0700137 " --minversion <number> Minimum combined kernel key version\n"
138 " and kernel version\n"
Bill Richardsona08b5c92010-06-30 21:59:43 -0700139 "\n",
140 progname);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700141 return 1;
142}
143
Bill Richardson249677d2010-06-23 11:16:37 -0700144static void Debug(const char *format, ...) {
145 if (!opt_debug)
146 return;
147
148 va_list ap;
149 va_start(ap, format);
150 fprintf(stderr, "DEBUG: ");
151 vfprintf(stderr, format, ap);
152 va_end(ap);
153}
154
Bill Richardson72e344d2012-03-19 12:47:18 -0700155static void Fatal(const char *format, ...) {
156 va_list ap;
157 va_start(ap, format);
158 fprintf(stderr, "ERROR: ");
159 vfprintf(stderr, format, ap);
160 va_end(ap);
161 exit(1);
162}
163
Bill Richardson2f6a71f2010-10-14 09:25:39 -0700164/* Return an explanation when fread() fails. */
165static const char *error_fread(FILE *fp) {
166 const char *retval = "beats me why";
167 if (feof(fp))
168 retval = "EOF";
169 else if (ferror(fp))
170 retval = strerror(errno);
171 clearerr(fp);
172 return retval;
173}
Randall Spangler7d6898d2010-06-11 09:22:13 -0700174
175/* Return the smallest integral multiple of [alignment] that is equal
176 * to or greater than [val]. Used to determine the number of
177 * pages/sectors/blocks/whatever needed to contain [val]
178 * items/bytes/etc. */
179static uint64_t roundup(uint64_t val, uint64_t alignment) {
180 uint64_t rem = val % alignment;
181 if ( rem )
182 return val + (alignment - rem);
183 return val;
184}
185
186
187/* Match regexp /\b--\b/ to delimit the start of the kernel commandline. If we
188 * don't find one, we'll use the whole thing. */
189static unsigned int find_cmdline_start(char *input, unsigned int max_len) {
190 int start = 0;
191 int i;
192 for(i = 0; i < max_len - 1 && input[i]; i++) {
193 if ('-' == input[i] && '-' == input[i + 1]) { /* found a "--" */
194 if ((i == 0 || ' ' == input[i - 1]) && /* nothing before it */
195 (i + 2 >= max_len || ' ' == input[i+2])) { /* nothing after it */
196 start = i+2; /* note: hope there's a trailing '\0' */
197 break;
198 }
199 }
200 }
201 while(' ' == input[start]) /* skip leading spaces */
202 start++;
203
204 return start;
205}
206
207
Bill Richardson72e344d2012-03-19 12:47:18 -0700208/****************************************************************************/
209/* Here are globals containing all the bits & pieces I'm working on. */
210
211/* The individual parts that go into the kernel blob */
212uint8_t *g_kernel_data;
213uint64_t g_kernel_size;
214uint8_t *g_param_data;
215uint64_t g_param_size;
216uint8_t *g_config_data;
217uint64_t g_config_size;
218uint8_t *g_bootloader_data;
219uint64_t g_bootloader_size;
220uint64_t g_bootloader_address;
Bill Richardsonc8b9ca62012-03-14 10:54:05 -0700221
222
Bill Richardson72e344d2012-03-19 12:47:18 -0700223/* The individual parts of the verification blob (including the data that
224 * immediately follows the headers) */
225VbKeyBlockHeader* g_keyblock;
226VbKernelPreambleHeader* g_preamble;
vbendebb2b0fcc2010-07-15 15:09:47 -0700227
Bill Richardson72e344d2012-03-19 12:47:18 -0700228/****************************************************************************/
Bill Richardsona08b5c92010-06-30 21:59:43 -0700229
vbendebb2b0fcc2010-07-15 15:09:47 -0700230/*
231 * Read the kernel command line from a file. Get rid of \n characters along
232 * the way and verify that the line fits into a 4K buffer.
233 *
234 * Return the buffer contaning the line on success (and set the line length
235 * using the passed in parameter), or NULL in case something goes wrong.
236 */
237static uint8_t* ReadConfigFile(const char* config_file, uint64_t* config_size)
238{
239 uint8_t* config_buf;
240 int ii;
241
242 config_buf = ReadFile(config_file, config_size);
243 Debug(" config file size=0x%" PRIx64 "\n", *config_size);
244 if (CROS_CONFIG_SIZE <= *config_size) { /* need room for trailing '\0' */
Randall Spangler32a65262011-06-27 10:49:11 -0700245 VbExError("Config file %s is too large (>= %d bytes)\n",
246 config_file, CROS_CONFIG_SIZE);
vbendebb2b0fcc2010-07-15 15:09:47 -0700247 return NULL;
248 }
249
250 /* Replace newlines with spaces */
251 for (ii = 0; ii < *config_size; ii++) {
252 if ('\n' == config_buf[ii]) {
253 config_buf[ii] = ' ';
254 }
255 }
256 return config_buf;
257}
258
Bill Richardson72e344d2012-03-19 12:47:18 -0700259
260/* Offset of kernel command line string from start of packed kernel blob */
261static uint64_t CmdLineOffset(VbKernelPreambleHeader *preamble) {
262 return preamble->bootloader_address - preamble->body_load_address -
263 CROS_CONFIG_SIZE - CROS_PARAMS_SIZE;
264}
265
266/* This initializes g_vmlinuz and g_param from a standard vmlinuz file.
267 * It returns 0 on error. */
268static int ImportVmlinuzFile(const char *vmlinuz_file, arch_t arch,
269 uint64_t kernel_body_load_address) {
270 uint8_t *kernel_buf;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700271 uint64_t kernel_size;
272 uint64_t kernel32_start = 0;
273 uint64_t kernel32_size = 0;
Kees Cooke0e4ed42013-04-10 18:05:51 -0700274 struct linux_kernel_params *params = NULL, *lh = NULL;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700275
276 /* Read the kernel */
Bill Richardson72e344d2012-03-19 12:47:18 -0700277 Debug("Reading %s\n", vmlinuz_file);
278 kernel_buf = ReadFile(vmlinuz_file, &kernel_size);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700279 if (!kernel_buf)
Bill Richardsona08b5c92010-06-30 21:59:43 -0700280 return 0;
Bill Richardson249677d2010-06-23 11:16:37 -0700281 Debug(" kernel file size=0x%" PRIx64 "\n", kernel_size);
Bill Richardson72e344d2012-03-19 12:47:18 -0700282 if (!kernel_size)
283 Fatal("Empty kernel file\n");
284
285 /* Go ahead and allocate the param region anyway. I don't think we need it
286 * for non-x86, but let's keep it for now. */
287 g_param_size = CROS_PARAMS_SIZE;
288 g_param_data= VbExMalloc(g_param_size);
289 Memset(g_param_data, 0, g_param_size);
290
291 /* Unless we're handling x86, the kernel is the kernel, so we're done. */
292 if (arch != ARCH_X86) {
293 g_kernel_data = kernel_buf;
294 g_kernel_size = kernel_size;
295 return 1;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700296 }
297
Bill Richardson72e344d2012-03-19 12:47:18 -0700298 /* The first part of the x86 vmlinuz is a header, followed by a real-mode
299 * boot stub. We only want the 32-bit part. */
Kees Cooke0e4ed42013-04-10 18:05:51 -0700300 lh = (struct linux_kernel_params *)kernel_buf;
Bill Richardson72e344d2012-03-19 12:47:18 -0700301 kernel32_start = (lh->setup_sects + 1) << 9;
302 if (kernel32_start >= kernel_size)
303 Fatal("Malformed kernel\n");
Randall Spangler7d6898d2010-06-11 09:22:13 -0700304 kernel32_size = kernel_size - kernel32_start;
Bill Richardson72e344d2012-03-19 12:47:18 -0700305
Bill Richardson249677d2010-06-23 11:16:37 -0700306 Debug(" kernel32_start=0x%" PRIx64 "\n", kernel32_start);
307 Debug(" kernel32_size=0x%" PRIx64 "\n", kernel32_size);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700308
Bill Richardson72e344d2012-03-19 12:47:18 -0700309 /* Keep just the 32-bit kernel. */
310 if (kernel32_size) {
311 g_kernel_size = kernel32_size;
312 g_kernel_data = VbExMalloc(g_kernel_size);
313 Memcpy(g_kernel_data, kernel_buf + kernel32_start, kernel32_size);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700314 }
Randall Spangler7d6898d2010-06-11 09:22:13 -0700315
Bill Richardson72e344d2012-03-19 12:47:18 -0700316 /* Copy the original zeropage data from kernel_buf into g_param_data, then
317 * tweak a few fields for our purposes */
318 params = (struct linux_kernel_params *)(g_param_data);
319 Memcpy(&(params->setup_sects), &(lh->setup_sects),
Kees Cooke0e4ed42013-04-10 18:05:51 -0700320 offsetof(struct linux_kernel_params, e820_entries)
321 - offsetof(struct linux_kernel_params, setup_sects));
Randall Spangler7d6898d2010-06-11 09:22:13 -0700322 params->boot_flag = 0;
Bill Richardson72e344d2012-03-19 12:47:18 -0700323 params->ramdisk_image = 0; /* we don't support initrd */
Randall Spangler7d6898d2010-06-11 09:22:13 -0700324 params->ramdisk_size = 0;
325 params->type_of_loader = 0xff;
Bill Richardson72e344d2012-03-19 12:47:18 -0700326 /* We need to point to the kernel commandline arg. On disk, it will come
327 * right after the 32-bit part of the kernel. */
328 params->cmd_line_ptr = kernel_body_load_address +
329 roundup(kernel32_size, CROS_ALIGN) +
330 find_cmdline_start((char *)g_config_data, g_config_size);
331 Debug(" cmdline_addr=0x%x\n", params->cmd_line_ptr);
Kees Cooke0e4ed42013-04-10 18:05:51 -0700332 Debug(" version=0x%x\n", params->version);
333 Debug(" kernel_alignment=0x%x\n", params->kernel_alignment);
334 Debug(" relocatable_kernel=0x%x\n", params->relocatable_kernel);
Che-Liang Chiou475bf442010-08-23 11:20:44 +0800335 /* A fake e820 memory map with 2 entries */
336 params->n_e820_entry = 2;
337 params->e820_entries[0].start_addr = 0x00000000;
338 params->e820_entries[0].segment_size = 0x00001000;
339 params->e820_entries[0].segment_type = E820_TYPE_RAM;
340 params->e820_entries[1].start_addr = 0xfffff000;
341 params->e820_entries[1].segment_size = 0x00001000;
342 params->e820_entries[1].segment_type = E820_TYPE_RESERVED;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700343
Bill Richardson72e344d2012-03-19 12:47:18 -0700344 /* done */
Randall Spangler32a65262011-06-27 10:49:11 -0700345 free(kernel_buf);
Bill Richardson72e344d2012-03-19 12:47:18 -0700346 return 1;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700347}
348
Bill Richardson72e344d2012-03-19 12:47:18 -0700349/* This returns just the kernel blob, with the verification blob separated
350 * and copied to new memory in g_keyblock and g_preamble. */
351static uint8_t* ReadOldBlobFromFileOrDie(const char *filename,
352 uint64_t* size_ptr) {
vbendebb2b0fcc2010-07-15 15:09:47 -0700353 FILE* fp = NULL;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700354 struct stat statbuf;
355 VbKeyBlockHeader* key_block;
356 VbKernelPreambleHeader* preamble;
357 uint64_t now = 0;
Bill Richardson72e344d2012-03-19 12:47:18 -0700358 uint8_t* buf;
359 uint8_t* kernel_blob_data;
360 uint64_t kernel_blob_size;
Vincent Palatin56c85db2012-09-05 15:35:12 -0700361 uint64_t file_size = 0;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700362
Bill Richardson72e344d2012-03-19 12:47:18 -0700363 if (0 != stat(filename, &statbuf))
364 Fatal("Unable to stat %s: %s\n", filename, strerror(errno));
Bill Richardsona08b5c92010-06-30 21:59:43 -0700365
Vincent Palatin56c85db2012-09-05 15:35:12 -0700366 if (S_ISBLK(statbuf.st_mode)) {
367 int fd;
368
369 if ((fd = open(filename, O_RDONLY)) >= 0) {
370 ioctl(fd, BLKGETSIZE64, &file_size);
371 close(fd);
372 }
373 } else {
374 file_size = statbuf.st_size;
375 }
376 Debug("%s size is 0x%" PRIx64 "\n", filename, file_size);
377 if (file_size < opt_pad)
Bill Richardson72e344d2012-03-19 12:47:18 -0700378 Fatal("%s is too small to be a valid kernel blob\n");
Bill Richardsona08b5c92010-06-30 21:59:43 -0700379
380 Debug("Reading %s\n", filename);
381 fp = fopen(filename, "rb");
Bill Richardson72e344d2012-03-19 12:47:18 -0700382 if (!fp)
383 Fatal("Unable to open file %s: %s\n", filename, strerror(errno));
Bill Richardsona08b5c92010-06-30 21:59:43 -0700384
Bill Richardson72e344d2012-03-19 12:47:18 -0700385 buf = VbExMalloc(opt_pad);
386 if (1 != fread(buf, opt_pad, 1, fp))
387 Fatal("Unable to read header from %s: %s\n", filename, error_fread(fp));
vbendebb2b0fcc2010-07-15 15:09:47 -0700388
Bill Richardson72e344d2012-03-19 12:47:18 -0700389 /* Sanity-check the key_block */
Bill Richardsona08b5c92010-06-30 21:59:43 -0700390 key_block = (VbKeyBlockHeader*)buf;
391 Debug("Keyblock is 0x%" PRIx64 " bytes\n", key_block->key_block_size);
392 now += key_block->key_block_size;
Vincent Palatin56c85db2012-09-05 15:35:12 -0700393 if (now > file_size)
Bill Richardson72e344d2012-03-19 12:47:18 -0700394 Fatal("key_block_size advances past the end of the blob\n");
395 if (now > opt_pad)
396 Fatal("key_block_size advances past %" PRIu64 " byte padding\n",
397 opt_pad);
398 /* LGTM */
399 g_keyblock = (VbKeyBlockHeader*)VbExMalloc(key_block->key_block_size);
400 Memcpy(g_keyblock, key_block, key_block->key_block_size);
Bill Richardsona08b5c92010-06-30 21:59:43 -0700401
Bill Richardson72e344d2012-03-19 12:47:18 -0700402 /* And the preamble */
Bill Richardsona08b5c92010-06-30 21:59:43 -0700403 preamble = (VbKernelPreambleHeader*)(buf + now);
404 Debug("Preamble is 0x%" PRIx64 " bytes\n", preamble->preamble_size);
405 now += preamble->preamble_size;
Vincent Palatin56c85db2012-09-05 15:35:12 -0700406 if (now > file_size)
Bill Richardson72e344d2012-03-19 12:47:18 -0700407 Fatal("preamble_size advances past the end of the blob\n");
408 if (now > opt_pad)
409 Fatal("preamble_size advances past %" PRIu64 " byte padding\n",
410 opt_pad);
411 /* LGTM */
412 Debug(" kernel_version = %d\n", preamble->kernel_version);
413 Debug(" bootloader_address = 0x%" PRIx64 "\n", preamble->bootloader_address);
414 Debug(" bootloader_size = 0x%" PRIx64 "\n", preamble->bootloader_size);
415 Debug(" kern_blob_size = 0x%" PRIx64 "\n",
416 preamble->body_signature.data_size);
417 g_preamble = (VbKernelPreambleHeader*)VbExMalloc(preamble->preamble_size);
418 Memcpy(g_preamble, preamble, preamble->preamble_size);
Bill Richardsona08b5c92010-06-30 21:59:43 -0700419
Bill Richardson72e344d2012-03-19 12:47:18 -0700420 /* Now for the kernel blob */
Bill Richardsona08b5c92010-06-30 21:59:43 -0700421 Debug("kernel blob is at offset 0x%" PRIx64 "\n", now);
Bill Richardson72e344d2012-03-19 12:47:18 -0700422 if (0 != fseek(fp, now, SEEK_SET))
423 Fatal("Unable to seek to 0x%" PRIx64 " in %s: %s\n", now, filename,
Bill Richardsona08b5c92010-06-30 21:59:43 -0700424 strerror(errno));
Bill Richardsona08b5c92010-06-30 21:59:43 -0700425
Bill Richardson72e344d2012-03-19 12:47:18 -0700426 /* Sanity check */
Vincent Palatin56c85db2012-09-05 15:35:12 -0700427 kernel_blob_size = file_size - now;
Bill Richardson72e344d2012-03-19 12:47:18 -0700428 if (!kernel_blob_size)
429 Fatal("No kernel blob found\n");
430 if (kernel_blob_size < preamble->body_signature.data_size)
431 fprintf(stderr, "Warning: kernel file only has 0x%" PRIx64 " bytes\n",
432 kernel_blob_size);
433 kernel_blob_data = VbExMalloc(kernel_blob_size);
Bill Richardsona08b5c92010-06-30 21:59:43 -0700434
Bill Richardson72e344d2012-03-19 12:47:18 -0700435 /* Read it in */
436 if (1 != fread(kernel_blob_data, kernel_blob_size, 1, fp))
437 Fatal("Unable to read kernel blob from %s: %s\n", filename,
Randall Spangler32a65262011-06-27 10:49:11 -0700438 error_fread(fp));
Bill Richardsona08b5c92010-06-30 21:59:43 -0700439
Bill Richardson72e344d2012-03-19 12:47:18 -0700440 /* Done */
441 VbExFree(buf);
Bill Richardsona08b5c92010-06-30 21:59:43 -0700442
Bill Richardson72e344d2012-03-19 12:47:18 -0700443 if (size_ptr)
444 *size_ptr = kernel_blob_size;
445
446 return kernel_blob_data;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700447}
448
449
Bill Richardson72e344d2012-03-19 12:47:18 -0700450/* Split a kernel blob into separate g_kernel, g_param, g_config, and
451 * g_bootloader parts. */
452static void UnpackKernelBlob(uint8_t *kernel_blob_data,
453 uint64_t kernel_blob_size) {
454
455 uint64_t k_blob_size = g_preamble->body_signature.data_size;
456 uint64_t k_blob_ofs = 0;
457 uint64_t b_size = g_preamble->bootloader_size;
458 uint64_t b_ofs = k_blob_ofs + g_preamble->bootloader_address -
459 g_preamble->body_load_address;
460 uint64_t p_ofs = b_ofs - CROS_CONFIG_SIZE;
461 uint64_t c_ofs = p_ofs - CROS_PARAMS_SIZE;
Bill Richardson72e344d2012-03-19 12:47:18 -0700462
463 Debug("k_blob_size = 0x%" PRIx64 "\n", k_blob_size );
464 Debug("k_blob_ofs = 0x%" PRIx64 "\n", k_blob_ofs );
465 Debug("b_size = 0x%" PRIx64 "\n", b_size );
466 Debug("b_ofs = 0x%" PRIx64 "\n", b_ofs );
467 Debug("p_ofs = 0x%" PRIx64 "\n", p_ofs );
468 Debug("c_ofs = 0x%" PRIx64 "\n", c_ofs );
469
470 g_kernel_size = c_ofs;
471 g_kernel_data = VbExMalloc(g_kernel_size);
472 Memcpy(g_kernel_data, kernel_blob_data, g_kernel_size);
473
474 g_param_size = CROS_PARAMS_SIZE;
475 g_param_data = VbExMalloc(g_param_size);
476 Memcpy(g_param_data, kernel_blob_data + p_ofs, g_param_size);
477
478 g_config_size = CROS_CONFIG_SIZE;
479 g_config_data = VbExMalloc(g_config_size);
480 Memcpy(g_config_data, kernel_blob_data + c_ofs, g_config_size);
481
482 g_bootloader_size = b_size;
483 g_bootloader_data = VbExMalloc(g_bootloader_size);
484 Memcpy(g_bootloader_data, kernel_blob_data + b_ofs, g_bootloader_size);
485}
486
487
488
489/****************************************************************************/
490
491static uint8_t* CreateKernelBlob(uint64_t kernel_body_load_address,
492 arch_t arch,
493 uint64_t *size_ptr) {
494 uint8_t *kern_blob;
495 uint64_t kern_blob_size;
496 uint64_t now;
497 uint64_t bootloader_size = roundup(g_bootloader_size, CROS_ALIGN);
498
499 /* Put the kernel blob together */
500 kern_blob_size = roundup(g_kernel_size, CROS_ALIGN) +
501 CROS_CONFIG_SIZE + CROS_PARAMS_SIZE + bootloader_size;
502 Debug("kern_blob_size=0x%" PRIx64 "\n", kern_blob_size);
503 kern_blob = VbExMalloc(kern_blob_size);
504 Memset(kern_blob, 0, kern_blob_size);
505 now = 0;
506
507 Debug("kernel goes at kern_blob+0x%" PRIx64 "\n", now);
508
509 Memcpy(kern_blob+now, g_kernel_data, g_kernel_size);
510 now += roundup(g_kernel_size, CROS_ALIGN);
511
512 Debug("config goes at kern_blob+0x%" PRIx64 "\n", now);
513 if (g_config_size)
514 Memcpy(kern_blob + now, g_config_data, g_config_size);
515 now += CROS_CONFIG_SIZE;
516
517 Debug("params goes at kern_blob+0x%" PRIx64 "\n", now);
518 if (g_param_size) {
519 Memcpy(kern_blob + now, g_param_data, g_param_size);
520 }
521 now += CROS_PARAMS_SIZE;
522
523 Debug("bootloader goes at kern_blob+0x%" PRIx64 "\n", now);
524 g_bootloader_address = kernel_body_load_address + now;
525 Debug(" bootloader_address=0x%" PRIx64 "\n", g_bootloader_address);
526 Debug(" bootloader_size=0x%" PRIx64 "\n", bootloader_size);
527 if (bootloader_size)
528 Memcpy(kern_blob + now, g_bootloader_data, g_bootloader_size);
529 now += bootloader_size;
530 Debug("end of kern_blob at kern_blob+0x%" PRIx64 "\n", now);
531
532 /* Done */
533 if (size_ptr)
534 *size_ptr = kern_blob_size;
535
536 return kern_blob;
537}
538
539static int Pack(const char* outfile,
540 uint8_t *kernel_blob,
541 uint64_t kernel_size,
542 int version,
543 uint64_t kernel_body_load_address,
544 VbPrivateKey* signpriv_key) {
Bill Richardsona08b5c92010-06-30 21:59:43 -0700545 VbSignature* body_sig;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700546 FILE* f;
547 uint64_t i;
Bill Richardsonc8b9ca62012-03-14 10:54:05 -0700548 uint64_t written = 0;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700549
Randall Spangler7d6898d2010-06-11 09:22:13 -0700550 /* Sign the kernel data */
Bill Richardson72e344d2012-03-19 12:47:18 -0700551 body_sig = CalculateSignature(kernel_blob, kernel_size, signpriv_key);
552 if (!body_sig)
553 Fatal("Error calculating body signature\n");
Randall Spangler7d6898d2010-06-11 09:22:13 -0700554
555 /* Create preamble */
Bill Richardson72e344d2012-03-19 12:47:18 -0700556 g_preamble = CreateKernelPreamble(version,
557 kernel_body_load_address,
558 g_bootloader_address,
559 roundup(g_bootloader_size, CROS_ALIGN),
560 body_sig,
561 opt_pad - g_keyblock->key_block_size,
562 signpriv_key);
563 if (!g_preamble) {
Randall Spangler32a65262011-06-27 10:49:11 -0700564 VbExError("Error creating preamble.\n");
Randall Spangler7d6898d2010-06-11 09:22:13 -0700565 return 1;
566 }
Randall Spangler7d6898d2010-06-11 09:22:13 -0700567 /* Write the output file */
Bill Richardson249677d2010-06-23 11:16:37 -0700568 Debug("writing %s...\n", outfile);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700569 f = fopen(outfile, "wb");
570 if (!f) {
Randall Spangler32a65262011-06-27 10:49:11 -0700571 VbExError("Can't open output file %s\n", outfile);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700572 return 1;
573 }
Bill Richardson72e344d2012-03-19 12:47:18 -0700574 Debug("0x%" PRIx64 " bytes of key_block\n", g_keyblock->key_block_size);
575 Debug("0x%" PRIx64 " bytes of preamble\n", g_preamble->preamble_size);
576 i = ((1 != fwrite(g_keyblock, g_keyblock->key_block_size, 1, f)) ||
577 (1 != fwrite(g_preamble, g_preamble->preamble_size, 1, f)));
Randall Spangler7d6898d2010-06-11 09:22:13 -0700578 if (i) {
Randall Spangler32a65262011-06-27 10:49:11 -0700579 VbExError("Can't write output file %s\n", outfile);
Bill Richardsona08b5c92010-06-30 21:59:43 -0700580 fclose(f);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700581 unlink(outfile);
582 return 1;
583 }
Bill Richardson72e344d2012-03-19 12:47:18 -0700584 written += g_keyblock->key_block_size;
585 written += g_preamble->preamble_size;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700586
Bill Richardson72e344d2012-03-19 12:47:18 -0700587 if (!opt_vblockonly) {
588 Debug("0x%" PRIx64 " bytes of kern_blob\n", kernel_size);
589 i = (1 != fwrite(kernel_blob, kernel_size, 1, f));
Bill Richardsona08b5c92010-06-30 21:59:43 -0700590 if (i) {
Bill Richardsona08b5c92010-06-30 21:59:43 -0700591 fclose(f);
592 unlink(outfile);
Bill Richardson72e344d2012-03-19 12:47:18 -0700593 Fatal("Can't write output file %s\n", outfile);
Bill Richardsona08b5c92010-06-30 21:59:43 -0700594 }
Bill Richardson72e344d2012-03-19 12:47:18 -0700595 written += kernel_size;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700596 }
Bill Richardsonc8b9ca62012-03-14 10:54:05 -0700597 Debug("0x%" PRIx64 " bytes total\n", written);
Bill Richardsona08b5c92010-06-30 21:59:43 -0700598 fclose(f);
599
Randall Spangler7d6898d2010-06-11 09:22:13 -0700600 /* Success */
601 return 0;
602}
603
Bill Richardson72e344d2012-03-19 12:47:18 -0700604static int Verify(uint8_t* kernel_blob,
605 uint64_t kernel_size,
606 VbPublicKey* signpub_key,
607 const char* keyblock_outfile,
608 uint64_t min_version) {
Randall Spangler7d6898d2010-06-11 09:22:13 -0700609 VbPublicKey* data_key;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700610 RSAPublicKey* rsa;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700611
Bill Richardson72e344d2012-03-19 12:47:18 -0700612 if (0 != KeyBlockVerify(g_keyblock, g_keyblock->key_block_size,
613 signpub_key, (0 == signpub_key)))
614 Fatal("Error verifying key block.\n");
Will Drewry9342f882010-10-26 10:22:05 -0500615
Randall Spangler7d6898d2010-06-11 09:22:13 -0700616 printf("Key block:\n");
Bill Richardson72e344d2012-03-19 12:47:18 -0700617 data_key = &g_keyblock->data_key;
618 if (opt_verbose)
619 printf(" Signature: %s\n", signpub_key ? "valid" : "ignored");
620 printf(" Size: 0x%" PRIx64 "\n", g_keyblock->key_block_size);
621 printf(" Flags: %" PRIu64 " ", g_keyblock->key_block_flags);
622 if (g_keyblock->key_block_flags & KEY_BLOCK_FLAG_DEVELOPER_0)
Bill Richardson60bcbe32010-09-09 14:53:56 -0700623 printf(" !DEV");
Bill Richardson72e344d2012-03-19 12:47:18 -0700624 if (g_keyblock->key_block_flags & KEY_BLOCK_FLAG_DEVELOPER_1)
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_RECOVERY_0)
Bill Richardson60bcbe32010-09-09 14:53:56 -0700627 printf(" !REC");
Bill Richardson72e344d2012-03-19 12:47:18 -0700628 if (g_keyblock->key_block_flags & KEY_BLOCK_FLAG_RECOVERY_1)
Bill Richardson60bcbe32010-09-09 14:53:56 -0700629 printf(" REC");
630 printf("\n");
Randall Spangler7d6898d2010-06-11 09:22:13 -0700631 printf(" Data key algorithm: %" PRIu64 " %s\n", data_key->algorithm,
632 (data_key->algorithm < kNumAlgorithms ?
633 algo_strings[data_key->algorithm] : "(invalid)"));
634 printf(" Data key version: %" PRIu64 "\n", data_key->key_version);
Bill Richardson60bcbe32010-09-09 14:53:56 -0700635 printf(" Data key sha1sum: ");
636 PrintPubKeySha1Sum(data_key);
637 printf("\n");
Randall Spangler7d6898d2010-06-11 09:22:13 -0700638
Bill Richardson72e344d2012-03-19 12:47:18 -0700639 if (keyblock_outfile) {
640 FILE* f = NULL;
641 f = fopen(keyblock_outfile, "wb");
642 if (!f)
643 Fatal("Can't open key block file %s\n", keyblock_outfile);
644 if (1 != fwrite(g_keyblock, g_keyblock->key_block_size, 1, f))
645 Fatal("Can't write key block file %s\n", keyblock_outfile);
646 fclose(f);
647 }
648
649 if (data_key->key_version < (min_version >> 16))
650 Fatal("Data key version %" PRIu64
Randall Spangler32a65262011-06-27 10:49:11 -0700651 " is lower than minimum %" PRIu64".\n",
652 data_key->key_version, (min_version >> 16));
Randall Spanglerae87b922011-05-12 13:27:28 -0700653
Bill Richardson72e344d2012-03-19 12:47:18 -0700654 rsa = PublicKeyToRSA(data_key);
655 if (!rsa)
656 Fatal("Error parsing data key.\n");
Randall Spangler7d6898d2010-06-11 09:22:13 -0700657
658 /* Verify preamble */
Bill Richardson72e344d2012-03-19 12:47:18 -0700659 if (0 != VerifyKernelPreamble(
660 g_preamble, g_preamble->preamble_size, rsa))
661 Fatal("Error verifying preamble.\n");
Randall Spangler7d6898d2010-06-11 09:22:13 -0700662
663 printf("Preamble:\n");
Bill Richardson72e344d2012-03-19 12:47:18 -0700664 printf(" Size: 0x%" PRIx64 "\n", g_preamble->preamble_size);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700665 printf(" Header version: %" PRIu32 ".%" PRIu32"\n",
Bill Richardson72e344d2012-03-19 12:47:18 -0700666 g_preamble->header_version_major, g_preamble->header_version_minor);
667 printf(" Kernel version: %" PRIu64 "\n", g_preamble->kernel_version);
668 printf(" Body load address: 0x%" PRIx64 "\n",
669 g_preamble->body_load_address);
Bill Richardson249677d2010-06-23 11:16:37 -0700670 printf(" Body size: 0x%" PRIx64 "\n",
Bill Richardson72e344d2012-03-19 12:47:18 -0700671 g_preamble->body_signature.data_size);
Randall Spangler87c13d82010-07-19 10:35:40 -0700672 printf(" Bootloader address: 0x%" PRIx64 "\n",
Bill Richardson72e344d2012-03-19 12:47:18 -0700673 g_preamble->bootloader_address);
674 printf(" Bootloader size: 0x%" PRIx64 "\n",
675 g_preamble->bootloader_size);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700676
Bill Richardson72e344d2012-03-19 12:47:18 -0700677 if (g_preamble->kernel_version < (min_version & 0xFFFF))
678 Fatal("Kernel version %" PRIu64 " is lower than minimum %" PRIu64 ".\n",
679 g_preamble->kernel_version, (min_version & 0xFFFF));
Randall Spanglerae87b922011-05-12 13:27:28 -0700680
Randall Spangler7d6898d2010-06-11 09:22:13 -0700681 /* Verify body */
Bill Richardson72e344d2012-03-19 12:47:18 -0700682 if (0 != VerifyData(kernel_blob, kernel_size,
683 &g_preamble->body_signature, rsa))
684 Fatal("Error verifying kernel body.\n");
Randall Spangler7d6898d2010-06-11 09:22:13 -0700685 printf("Body verification succeeded.\n");
vbendebb2b0fcc2010-07-15 15:09:47 -0700686
vbendebb2b0fcc2010-07-15 15:09:47 -0700687
Bill Richardson72e344d2012-03-19 12:47:18 -0700688 if (opt_verbose)
689 printf("Config:\n%s\n", kernel_blob + CmdLineOffset(g_preamble));
vbendebb2b0fcc2010-07-15 15:09:47 -0700690
Bill Richardson72e344d2012-03-19 12:47:18 -0700691 return 0;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700692}
693
Bill Richardson72e344d2012-03-19 12:47:18 -0700694/****************************************************************************/
Randall Spangler7d6898d2010-06-11 09:22:13 -0700695
696int main(int argc, char* argv[]) {
Randall Spangler7d6898d2010-06-11 09:22:13 -0700697 char* filename = NULL;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700698 char* oldfile = NULL;
Bill Richardson72e344d2012-03-19 12:47:18 -0700699 char* keyblock_file = NULL;
700 char* signpubkey_file = NULL;
701 char* signprivkey_file = NULL;
702 char* version_str = NULL;
vbendeb00b90882010-10-21 13:46:16 -0700703 int version = -1;
Bill Richardson72e344d2012-03-19 12:47:18 -0700704 char* vmlinuz_file = NULL;
705 char* bootloader_file = NULL;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700706 char* config_file = NULL;
Bill Richardson72e344d2012-03-19 12:47:18 -0700707 arch_t arch = ARCH_X86;
708 char *address_str = NULL;
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +0800709 uint64_t kernel_body_load_address = CROS_32BIT_ENTRY_ADDR;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700710 int mode = 0;
711 int parse_error = 0;
Randall Spanglerae87b922011-05-12 13:27:28 -0700712 uint64_t min_version = 0;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700713 char* e;
Bill Richardson72e344d2012-03-19 12:47:18 -0700714 int i;
715 VbPrivateKey* signpriv_key = NULL;
716 VbPublicKey* signpub_key = NULL;
717 uint8_t* kernel_blob = NULL;
718 uint64_t kernel_size = 0;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700719
720 char *progname = strrchr(argv[0], '/');
721 if (progname)
722 progname++;
723 else
724 progname = argv[0];
725
vbendebb2b0fcc2010-07-15 15:09:47 -0700726 while (((i = getopt_long(argc, argv, ":", long_opts, NULL)) != -1) &&
727 !parse_error) {
Randall Spangler7d6898d2010-06-11 09:22:13 -0700728 switch (i) {
Bill Richardson72e344d2012-03-19 12:47:18 -0700729 default:
730 case '?':
731 /* Unhandled option */
732 parse_error = 1;
733 break;
734
735 case 0:
736 /* silently handled option */
737 break;
738
739 case OPT_MODE_PACK:
740 case OPT_MODE_REPACK:
741 case OPT_MODE_VERIFY:
742 if (mode && (mode != i)) {
743 fprintf(stderr, "Only a single mode can be specified\n");
Randall Spangler7d6898d2010-06-11 09:22:13 -0700744 parse_error = 1;
745 break;
Bill Richardson72e344d2012-03-19 12:47:18 -0700746 }
747 mode = i;
748 filename = optarg;
749 break;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700750
Bill Richardson72e344d2012-03-19 12:47:18 -0700751 case OPT_ARCH:
752 /* check the first 3 characters to also detect x86_64 */
753 if ((!strncasecmp(optarg, "x86", 3)) ||
754 (!strcasecmp(optarg, "amd64")))
755 arch = ARCH_X86;
756 else if (!strcasecmp(optarg, "arm"))
757 arch = ARCH_ARM;
758 else {
759 fprintf(stderr, "Unknown architecture string: %s\n", optarg);
760 parse_error = 1;
761 }
762 break;
Bill Richardson4f36ef32010-08-09 17:50:14 -0700763
Bill Richardson72e344d2012-03-19 12:47:18 -0700764 case OPT_OLDBLOB:
765 oldfile = optarg;
766 break;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700767
Bill Richardson72e344d2012-03-19 12:47:18 -0700768 case OPT_KLOADADDR:
769 address_str = optarg;
770 kernel_body_load_address = strtoul(optarg, &e, 0);
771 if (!*optarg || (e && *e)) {
772 fprintf(stderr, "Invalid --kloadaddr\n");
773 parse_error = 1;
774 }
775 break;
Che-Liang Chiou03762032011-02-22 11:16:51 +0800776
Bill Richardson72e344d2012-03-19 12:47:18 -0700777 case OPT_KEYBLOCK:
778 keyblock_file = optarg;
779 break;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700780
Bill Richardson72e344d2012-03-19 12:47:18 -0700781 case OPT_SIGNPUBKEY:
782 signpubkey_file = optarg;
783 break;
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +0800784
Bill Richardson72e344d2012-03-19 12:47:18 -0700785 case OPT_SIGNPRIVATE:
786 signprivkey_file = optarg;
787 break;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700788
Bill Richardson72e344d2012-03-19 12:47:18 -0700789 case OPT_VMLINUZ:
790 vmlinuz_file = optarg;
791 break;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700792
Bill Richardson72e344d2012-03-19 12:47:18 -0700793 case OPT_BOOTLOADER:
794 bootloader_file = optarg;
795 break;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700796
Bill Richardson72e344d2012-03-19 12:47:18 -0700797 case OPT_CONFIG:
798 config_file = optarg;
799 break;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700800
Bill Richardson72e344d2012-03-19 12:47:18 -0700801 case OPT_VBLOCKONLY:
802 opt_vblockonly = 1;
803 break;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700804
Bill Richardson72e344d2012-03-19 12:47:18 -0700805 case OPT_VERSION:
806 version_str = optarg;
807 version = strtoul(optarg, &e, 0);
808 if (!*optarg || (e && *e)) {
809 fprintf(stderr, "Invalid --version\n");
810 parse_error = 1;
811 }
812 break;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700813
Bill Richardson72e344d2012-03-19 12:47:18 -0700814 case OPT_MINVERSION:
815 min_version = strtoul(optarg, &e, 0);
816 if (!*optarg || (e && *e)) {
817 fprintf(stderr, "Invalid --minversion\n");
818 parse_error = 1;
819 }
820 break;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700821
Bill Richardson72e344d2012-03-19 12:47:18 -0700822 case OPT_PAD:
823 opt_pad = strtoul(optarg, &e, 0);
824 if (!*optarg || (e && *e)) {
825 fprintf(stderr, "Invalid --pad\n");
826 parse_error = 1;
827 }
828 break;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700829 }
830 }
831
832 if (parse_error)
Bill Richardsona08b5c92010-06-30 21:59:43 -0700833 return PrintHelp(progname);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700834
835 switch(mode) {
Bill Richardson72e344d2012-03-19 12:47:18 -0700836 case OPT_MODE_PACK:
Bill Richardsona08b5c92010-06-30 21:59:43 -0700837
Bill Richardson72e344d2012-03-19 12:47:18 -0700838 /* Required */
vbendebb2b0fcc2010-07-15 15:09:47 -0700839
Bill Richardson72e344d2012-03-19 12:47:18 -0700840 if (!keyblock_file)
841 Fatal("Missing required keyblock file.\n");
Bill Richardsona08b5c92010-06-30 21:59:43 -0700842
Bill Richardson72e344d2012-03-19 12:47:18 -0700843 g_keyblock = (VbKeyBlockHeader*)ReadFile(keyblock_file, 0);
844 if (!g_keyblock)
845 Fatal("Error reading key block.\n");
Bill Richardsona08b5c92010-06-30 21:59:43 -0700846
Bill Richardson72e344d2012-03-19 12:47:18 -0700847 if (!signprivkey_file)
848 Fatal("Missing required signprivate file.\n");
849
850 signpriv_key = PrivateKeyRead(signprivkey_file);
851 if (!signpriv_key)
852 Fatal("Error reading signing key.\n");
853
854 /* Optional */
855
856 if (config_file) {
857 Debug("Reading %s\n", config_file);
858 g_config_data = ReadConfigFile(config_file, &g_config_size);
Lucian Cojocar2312ab62012-07-30 15:21:49 -0700859 if (!g_config_data)
860 Fatal("Error reading config file.\n");
Bill Richardson72e344d2012-03-19 12:47:18 -0700861 }
862
863 if (vmlinuz_file)
864 if (!ImportVmlinuzFile(vmlinuz_file, arch, kernel_body_load_address))
865 Fatal("Error reading kernel file.\n");
866
867 if (bootloader_file) {
868 Debug("Reading %s\n", bootloader_file);
869 g_bootloader_data = ReadFile(bootloader_file, &g_bootloader_size);
870 if (!g_bootloader_data)
871 Fatal("Error reading bootloader file.\n");
872 Debug(" bootloader file size=0x%" PRIx64 "\n", g_bootloader_size);
873 }
874
875 /* Do it */
876
877 kernel_blob = CreateKernelBlob(kernel_body_load_address, arch,
878 &kernel_size);
879
880 return Pack(filename, kernel_blob, kernel_size,
881 version, kernel_body_load_address,
882 signpriv_key);
883
884 case OPT_MODE_REPACK:
885
886 /* Required */
887
888 if (!signprivkey_file)
889 Fatal("Missing required signprivate file.\n");
890
891 signpriv_key = PrivateKeyRead(signprivkey_file);
892 if (!signpriv_key)
893 Fatal("Error reading signing key.\n");
894
895 if (!oldfile)
896 Fatal("Missing previously packed blob.\n");
897
898 /* Load the old blob */
899
900 kernel_blob = ReadOldBlobFromFileOrDie(oldfile, &kernel_size);
901 if (0 != Verify(kernel_blob, kernel_size, 0, 0, 0))
902 Fatal("The oldblob doesn't verify\n");
903
904 /* Take it apart */
905
906 UnpackKernelBlob(kernel_blob, kernel_size);
907 free(kernel_blob);
908
909 /* Load optional params */
910
911 if (!version_str)
912 version = g_preamble->kernel_version;
913
914 if (!address_str)
915 kernel_body_load_address = g_preamble->body_load_address;
916
917 if (config_file) {
918 if (g_config_data)
919 free(g_config_data);
920 Debug("Reading %s\n", config_file);
921 g_config_data = ReadConfigFile(config_file, &g_config_size);
Lucian Cojocar2312ab62012-07-30 15:21:49 -0700922 if (!g_config_data)
923 Fatal("Error reading config file.\n");
Bill Richardson72e344d2012-03-19 12:47:18 -0700924 }
925
926 if (keyblock_file) {
927 if (g_keyblock)
928 free(g_keyblock);
929 g_keyblock = (VbKeyBlockHeader*)ReadFile(keyblock_file, 0);
930 if (!g_keyblock)
931 Fatal("Error reading key block.\n");
932 }
933
934 /* Put it back together */
935
936 kernel_blob = CreateKernelBlob(kernel_body_load_address, arch,
937 &kernel_size);
938
939 return Pack(filename, kernel_blob, kernel_size,
940 version, kernel_body_load_address,
941 signpriv_key);
942
943
944 case OPT_MODE_VERIFY:
945
946 /* Optional */
947
948 if (signpubkey_file) {
949 signpub_key = PublicKeyRead(signpubkey_file);
950 if (!signpub_key)
951 Fatal("Error reading public key.\n");
952 }
953
954 /* Do it */
955
956 kernel_blob = ReadOldBlobFromFileOrDie(filename, &kernel_size);
957
958 return Verify(kernel_blob, kernel_size, signpub_key,
959 keyblock_file, min_version);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700960 }
Bill Richardson72e344d2012-03-19 12:47:18 -0700961
962 fprintf(stderr, "You must specify a mode: --pack, --repack or --verify\n");
963 return PrintHelp(progname);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700964}