blob: 615ce3039dab61358c3bf6eb5ec80f204d3f9e9c [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;
Bill Richardson72e344d2012-03-19 12:47:18 -0700274 struct linux_kernel_header* lh = 0;
275 struct linux_kernel_params* params = 0;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700276
277 /* Read the kernel */
Bill Richardson72e344d2012-03-19 12:47:18 -0700278 Debug("Reading %s\n", vmlinuz_file);
279 kernel_buf = ReadFile(vmlinuz_file, &kernel_size);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700280 if (!kernel_buf)
Bill Richardsona08b5c92010-06-30 21:59:43 -0700281 return 0;
Bill Richardson249677d2010-06-23 11:16:37 -0700282 Debug(" kernel file size=0x%" PRIx64 "\n", kernel_size);
Bill Richardson72e344d2012-03-19 12:47:18 -0700283 if (!kernel_size)
284 Fatal("Empty kernel file\n");
285
286 /* Go ahead and allocate the param region anyway. I don't think we need it
287 * for non-x86, but let's keep it for now. */
288 g_param_size = CROS_PARAMS_SIZE;
289 g_param_data= VbExMalloc(g_param_size);
290 Memset(g_param_data, 0, g_param_size);
291
292 /* Unless we're handling x86, the kernel is the kernel, so we're done. */
293 if (arch != ARCH_X86) {
294 g_kernel_data = kernel_buf;
295 g_kernel_size = kernel_size;
296 return 1;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700297 }
298
Bill Richardson72e344d2012-03-19 12:47:18 -0700299 /* The first part of the x86 vmlinuz is a header, followed by a real-mode
300 * boot stub. We only want the 32-bit part. */
301 lh = (struct linux_kernel_header *)kernel_buf;
302 kernel32_start = (lh->setup_sects + 1) << 9;
303 if (kernel32_start >= kernel_size)
304 Fatal("Malformed kernel\n");
Randall Spangler7d6898d2010-06-11 09:22:13 -0700305 kernel32_size = kernel_size - kernel32_start;
Bill Richardson72e344d2012-03-19 12:47:18 -0700306
Bill Richardson249677d2010-06-23 11:16:37 -0700307 Debug(" kernel32_start=0x%" PRIx64 "\n", kernel32_start);
308 Debug(" kernel32_size=0x%" PRIx64 "\n", kernel32_size);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700309
Bill Richardson72e344d2012-03-19 12:47:18 -0700310 /* Keep just the 32-bit kernel. */
311 if (kernel32_size) {
312 g_kernel_size = kernel32_size;
313 g_kernel_data = VbExMalloc(g_kernel_size);
314 Memcpy(g_kernel_data, kernel_buf + kernel32_start, kernel32_size);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700315 }
Randall Spangler7d6898d2010-06-11 09:22:13 -0700316
Bill Richardson72e344d2012-03-19 12:47:18 -0700317 /* Copy the original zeropage data from kernel_buf into g_param_data, then
318 * tweak a few fields for our purposes */
319 params = (struct linux_kernel_params *)(g_param_data);
320 Memcpy(&(params->setup_sects), &(lh->setup_sects),
321 sizeof(*lh) - offsetof(struct linux_kernel_header, 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);
Che-Liang Chiou475bf442010-08-23 11:20:44 +0800332 /* A fake e820 memory map with 2 entries */
333 params->n_e820_entry = 2;
334 params->e820_entries[0].start_addr = 0x00000000;
335 params->e820_entries[0].segment_size = 0x00001000;
336 params->e820_entries[0].segment_type = E820_TYPE_RAM;
337 params->e820_entries[1].start_addr = 0xfffff000;
338 params->e820_entries[1].segment_size = 0x00001000;
339 params->e820_entries[1].segment_type = E820_TYPE_RESERVED;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700340
Bill Richardson72e344d2012-03-19 12:47:18 -0700341 /* done */
Randall Spangler32a65262011-06-27 10:49:11 -0700342 free(kernel_buf);
Bill Richardson72e344d2012-03-19 12:47:18 -0700343 return 1;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700344}
345
Bill Richardson72e344d2012-03-19 12:47:18 -0700346/* This returns just the kernel blob, with the verification blob separated
347 * and copied to new memory in g_keyblock and g_preamble. */
348static uint8_t* ReadOldBlobFromFileOrDie(const char *filename,
349 uint64_t* size_ptr) {
vbendebb2b0fcc2010-07-15 15:09:47 -0700350 FILE* fp = NULL;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700351 struct stat statbuf;
352 VbKeyBlockHeader* key_block;
353 VbKernelPreambleHeader* preamble;
354 uint64_t now = 0;
Bill Richardson72e344d2012-03-19 12:47:18 -0700355 uint8_t* buf;
356 uint8_t* kernel_blob_data;
357 uint64_t kernel_blob_size;
Vincent Palatin56c85db2012-09-05 15:35:12 -0700358 uint64_t file_size = 0;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700359
Bill Richardson72e344d2012-03-19 12:47:18 -0700360 if (0 != stat(filename, &statbuf))
361 Fatal("Unable to stat %s: %s\n", filename, strerror(errno));
Bill Richardsona08b5c92010-06-30 21:59:43 -0700362
Vincent Palatin56c85db2012-09-05 15:35:12 -0700363 if (S_ISBLK(statbuf.st_mode)) {
364 int fd;
365
366 if ((fd = open(filename, O_RDONLY)) >= 0) {
367 ioctl(fd, BLKGETSIZE64, &file_size);
368 close(fd);
369 }
370 } else {
371 file_size = statbuf.st_size;
372 }
373 Debug("%s size is 0x%" PRIx64 "\n", filename, file_size);
374 if (file_size < opt_pad)
Bill Richardson72e344d2012-03-19 12:47:18 -0700375 Fatal("%s is too small to be a valid kernel blob\n");
Bill Richardsona08b5c92010-06-30 21:59:43 -0700376
377 Debug("Reading %s\n", filename);
378 fp = fopen(filename, "rb");
Bill Richardson72e344d2012-03-19 12:47:18 -0700379 if (!fp)
380 Fatal("Unable to open file %s: %s\n", filename, strerror(errno));
Bill Richardsona08b5c92010-06-30 21:59:43 -0700381
Bill Richardson72e344d2012-03-19 12:47:18 -0700382 buf = VbExMalloc(opt_pad);
383 if (1 != fread(buf, opt_pad, 1, fp))
384 Fatal("Unable to read header from %s: %s\n", filename, error_fread(fp));
vbendebb2b0fcc2010-07-15 15:09:47 -0700385
Bill Richardson72e344d2012-03-19 12:47:18 -0700386 /* Sanity-check the key_block */
Bill Richardsona08b5c92010-06-30 21:59:43 -0700387 key_block = (VbKeyBlockHeader*)buf;
388 Debug("Keyblock is 0x%" PRIx64 " bytes\n", key_block->key_block_size);
389 now += key_block->key_block_size;
Vincent Palatin56c85db2012-09-05 15:35:12 -0700390 if (now > file_size)
Bill Richardson72e344d2012-03-19 12:47:18 -0700391 Fatal("key_block_size advances past the end of the blob\n");
392 if (now > opt_pad)
393 Fatal("key_block_size advances past %" PRIu64 " byte padding\n",
394 opt_pad);
395 /* LGTM */
396 g_keyblock = (VbKeyBlockHeader*)VbExMalloc(key_block->key_block_size);
397 Memcpy(g_keyblock, key_block, key_block->key_block_size);
Bill Richardsona08b5c92010-06-30 21:59:43 -0700398
Bill Richardson72e344d2012-03-19 12:47:18 -0700399 /* And the preamble */
Bill Richardsona08b5c92010-06-30 21:59:43 -0700400 preamble = (VbKernelPreambleHeader*)(buf + now);
401 Debug("Preamble is 0x%" PRIx64 " bytes\n", preamble->preamble_size);
402 now += preamble->preamble_size;
Vincent Palatin56c85db2012-09-05 15:35:12 -0700403 if (now > file_size)
Bill Richardson72e344d2012-03-19 12:47:18 -0700404 Fatal("preamble_size advances past the end of the blob\n");
405 if (now > opt_pad)
406 Fatal("preamble_size advances past %" PRIu64 " byte padding\n",
407 opt_pad);
408 /* LGTM */
409 Debug(" kernel_version = %d\n", preamble->kernel_version);
410 Debug(" bootloader_address = 0x%" PRIx64 "\n", preamble->bootloader_address);
411 Debug(" bootloader_size = 0x%" PRIx64 "\n", preamble->bootloader_size);
412 Debug(" kern_blob_size = 0x%" PRIx64 "\n",
413 preamble->body_signature.data_size);
414 g_preamble = (VbKernelPreambleHeader*)VbExMalloc(preamble->preamble_size);
415 Memcpy(g_preamble, preamble, preamble->preamble_size);
Bill Richardsona08b5c92010-06-30 21:59:43 -0700416
Bill Richardson72e344d2012-03-19 12:47:18 -0700417 /* Now for the kernel blob */
Bill Richardsona08b5c92010-06-30 21:59:43 -0700418 Debug("kernel blob is at offset 0x%" PRIx64 "\n", now);
Bill Richardson72e344d2012-03-19 12:47:18 -0700419 if (0 != fseek(fp, now, SEEK_SET))
420 Fatal("Unable to seek to 0x%" PRIx64 " in %s: %s\n", now, filename,
Bill Richardsona08b5c92010-06-30 21:59:43 -0700421 strerror(errno));
Bill Richardsona08b5c92010-06-30 21:59:43 -0700422
Bill Richardson72e344d2012-03-19 12:47:18 -0700423 /* Sanity check */
Vincent Palatin56c85db2012-09-05 15:35:12 -0700424 kernel_blob_size = file_size - now;
Bill Richardson72e344d2012-03-19 12:47:18 -0700425 if (!kernel_blob_size)
426 Fatal("No kernel blob found\n");
427 if (kernel_blob_size < preamble->body_signature.data_size)
428 fprintf(stderr, "Warning: kernel file only has 0x%" PRIx64 " bytes\n",
429 kernel_blob_size);
430 kernel_blob_data = VbExMalloc(kernel_blob_size);
Bill Richardsona08b5c92010-06-30 21:59:43 -0700431
Bill Richardson72e344d2012-03-19 12:47:18 -0700432 /* Read it in */
433 if (1 != fread(kernel_blob_data, kernel_blob_size, 1, fp))
434 Fatal("Unable to read kernel blob from %s: %s\n", filename,
Randall Spangler32a65262011-06-27 10:49:11 -0700435 error_fread(fp));
Bill Richardsona08b5c92010-06-30 21:59:43 -0700436
Bill Richardson72e344d2012-03-19 12:47:18 -0700437 /* Done */
438 VbExFree(buf);
Bill Richardsona08b5c92010-06-30 21:59:43 -0700439
Bill Richardson72e344d2012-03-19 12:47:18 -0700440 if (size_ptr)
441 *size_ptr = kernel_blob_size;
442
443 return kernel_blob_data;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700444}
445
446
Bill Richardson72e344d2012-03-19 12:47:18 -0700447/* Split a kernel blob into separate g_kernel, g_param, g_config, and
448 * g_bootloader parts. */
449static void UnpackKernelBlob(uint8_t *kernel_blob_data,
450 uint64_t kernel_blob_size) {
451
452 uint64_t k_blob_size = g_preamble->body_signature.data_size;
453 uint64_t k_blob_ofs = 0;
454 uint64_t b_size = g_preamble->bootloader_size;
455 uint64_t b_ofs = k_blob_ofs + g_preamble->bootloader_address -
456 g_preamble->body_load_address;
457 uint64_t p_ofs = b_ofs - CROS_CONFIG_SIZE;
458 uint64_t c_ofs = p_ofs - CROS_PARAMS_SIZE;
Bill Richardson72e344d2012-03-19 12:47:18 -0700459
460 Debug("k_blob_size = 0x%" PRIx64 "\n", k_blob_size );
461 Debug("k_blob_ofs = 0x%" PRIx64 "\n", k_blob_ofs );
462 Debug("b_size = 0x%" PRIx64 "\n", b_size );
463 Debug("b_ofs = 0x%" PRIx64 "\n", b_ofs );
464 Debug("p_ofs = 0x%" PRIx64 "\n", p_ofs );
465 Debug("c_ofs = 0x%" PRIx64 "\n", c_ofs );
466
467 g_kernel_size = c_ofs;
468 g_kernel_data = VbExMalloc(g_kernel_size);
469 Memcpy(g_kernel_data, kernel_blob_data, g_kernel_size);
470
471 g_param_size = CROS_PARAMS_SIZE;
472 g_param_data = VbExMalloc(g_param_size);
473 Memcpy(g_param_data, kernel_blob_data + p_ofs, g_param_size);
474
475 g_config_size = CROS_CONFIG_SIZE;
476 g_config_data = VbExMalloc(g_config_size);
477 Memcpy(g_config_data, kernel_blob_data + c_ofs, g_config_size);
478
479 g_bootloader_size = b_size;
480 g_bootloader_data = VbExMalloc(g_bootloader_size);
481 Memcpy(g_bootloader_data, kernel_blob_data + b_ofs, g_bootloader_size);
482}
483
484
485
486/****************************************************************************/
487
488static uint8_t* CreateKernelBlob(uint64_t kernel_body_load_address,
489 arch_t arch,
490 uint64_t *size_ptr) {
491 uint8_t *kern_blob;
492 uint64_t kern_blob_size;
493 uint64_t now;
494 uint64_t bootloader_size = roundup(g_bootloader_size, CROS_ALIGN);
495
496 /* Put the kernel blob together */
497 kern_blob_size = roundup(g_kernel_size, CROS_ALIGN) +
498 CROS_CONFIG_SIZE + CROS_PARAMS_SIZE + bootloader_size;
499 Debug("kern_blob_size=0x%" PRIx64 "\n", kern_blob_size);
500 kern_blob = VbExMalloc(kern_blob_size);
501 Memset(kern_blob, 0, kern_blob_size);
502 now = 0;
503
504 Debug("kernel goes at kern_blob+0x%" PRIx64 "\n", now);
505
506 Memcpy(kern_blob+now, g_kernel_data, g_kernel_size);
507 now += roundup(g_kernel_size, CROS_ALIGN);
508
509 Debug("config goes at kern_blob+0x%" PRIx64 "\n", now);
510 if (g_config_size)
511 Memcpy(kern_blob + now, g_config_data, g_config_size);
512 now += CROS_CONFIG_SIZE;
513
514 Debug("params goes at kern_blob+0x%" PRIx64 "\n", now);
515 if (g_param_size) {
516 Memcpy(kern_blob + now, g_param_data, g_param_size);
517 }
518 now += CROS_PARAMS_SIZE;
519
520 Debug("bootloader goes at kern_blob+0x%" PRIx64 "\n", now);
521 g_bootloader_address = kernel_body_load_address + now;
522 Debug(" bootloader_address=0x%" PRIx64 "\n", g_bootloader_address);
523 Debug(" bootloader_size=0x%" PRIx64 "\n", bootloader_size);
524 if (bootloader_size)
525 Memcpy(kern_blob + now, g_bootloader_data, g_bootloader_size);
526 now += bootloader_size;
527 Debug("end of kern_blob at kern_blob+0x%" PRIx64 "\n", now);
528
529 /* Done */
530 if (size_ptr)
531 *size_ptr = kern_blob_size;
532
533 return kern_blob;
534}
535
536static int Pack(const char* outfile,
537 uint8_t *kernel_blob,
538 uint64_t kernel_size,
539 int version,
540 uint64_t kernel_body_load_address,
541 VbPrivateKey* signpriv_key) {
Bill Richardsona08b5c92010-06-30 21:59:43 -0700542 VbSignature* body_sig;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700543 FILE* f;
544 uint64_t i;
Bill Richardsonc8b9ca62012-03-14 10:54:05 -0700545 uint64_t written = 0;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700546
Randall Spangler7d6898d2010-06-11 09:22:13 -0700547 /* Sign the kernel data */
Bill Richardson72e344d2012-03-19 12:47:18 -0700548 body_sig = CalculateSignature(kernel_blob, kernel_size, signpriv_key);
549 if (!body_sig)
550 Fatal("Error calculating body signature\n");
Randall Spangler7d6898d2010-06-11 09:22:13 -0700551
552 /* Create preamble */
Bill Richardson72e344d2012-03-19 12:47:18 -0700553 g_preamble = CreateKernelPreamble(version,
554 kernel_body_load_address,
555 g_bootloader_address,
556 roundup(g_bootloader_size, CROS_ALIGN),
557 body_sig,
558 opt_pad - g_keyblock->key_block_size,
559 signpriv_key);
560 if (!g_preamble) {
Randall Spangler32a65262011-06-27 10:49:11 -0700561 VbExError("Error creating preamble.\n");
Randall Spangler7d6898d2010-06-11 09:22:13 -0700562 return 1;
563 }
Randall Spangler7d6898d2010-06-11 09:22:13 -0700564 /* Write the output file */
Bill Richardson249677d2010-06-23 11:16:37 -0700565 Debug("writing %s...\n", outfile);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700566 f = fopen(outfile, "wb");
567 if (!f) {
Randall Spangler32a65262011-06-27 10:49:11 -0700568 VbExError("Can't open output file %s\n", outfile);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700569 return 1;
570 }
Bill Richardson72e344d2012-03-19 12:47:18 -0700571 Debug("0x%" PRIx64 " bytes of key_block\n", g_keyblock->key_block_size);
572 Debug("0x%" PRIx64 " bytes of preamble\n", g_preamble->preamble_size);
573 i = ((1 != fwrite(g_keyblock, g_keyblock->key_block_size, 1, f)) ||
574 (1 != fwrite(g_preamble, g_preamble->preamble_size, 1, f)));
Randall Spangler7d6898d2010-06-11 09:22:13 -0700575 if (i) {
Randall Spangler32a65262011-06-27 10:49:11 -0700576 VbExError("Can't write output file %s\n", outfile);
Bill Richardsona08b5c92010-06-30 21:59:43 -0700577 fclose(f);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700578 unlink(outfile);
579 return 1;
580 }
Bill Richardson72e344d2012-03-19 12:47:18 -0700581 written += g_keyblock->key_block_size;
582 written += g_preamble->preamble_size;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700583
Bill Richardson72e344d2012-03-19 12:47:18 -0700584 if (!opt_vblockonly) {
585 Debug("0x%" PRIx64 " bytes of kern_blob\n", kernel_size);
586 i = (1 != fwrite(kernel_blob, kernel_size, 1, f));
Bill Richardsona08b5c92010-06-30 21:59:43 -0700587 if (i) {
Bill Richardsona08b5c92010-06-30 21:59:43 -0700588 fclose(f);
589 unlink(outfile);
Bill Richardson72e344d2012-03-19 12:47:18 -0700590 Fatal("Can't write output file %s\n", outfile);
Bill Richardsona08b5c92010-06-30 21:59:43 -0700591 }
Bill Richardson72e344d2012-03-19 12:47:18 -0700592 written += kernel_size;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700593 }
Bill Richardsonc8b9ca62012-03-14 10:54:05 -0700594 Debug("0x%" PRIx64 " bytes total\n", written);
Bill Richardsona08b5c92010-06-30 21:59:43 -0700595 fclose(f);
596
Randall Spangler7d6898d2010-06-11 09:22:13 -0700597 /* Success */
598 return 0;
599}
600
Bill Richardson72e344d2012-03-19 12:47:18 -0700601static int Verify(uint8_t* kernel_blob,
602 uint64_t kernel_size,
603 VbPublicKey* signpub_key,
604 const char* keyblock_outfile,
605 uint64_t min_version) {
Randall Spangler7d6898d2010-06-11 09:22:13 -0700606 VbPublicKey* data_key;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700607 RSAPublicKey* rsa;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700608
Bill Richardson72e344d2012-03-19 12:47:18 -0700609 if (0 != KeyBlockVerify(g_keyblock, g_keyblock->key_block_size,
610 signpub_key, (0 == signpub_key)))
611 Fatal("Error verifying key block.\n");
Will Drewry9342f882010-10-26 10:22:05 -0500612
Randall Spangler7d6898d2010-06-11 09:22:13 -0700613 printf("Key block:\n");
Bill Richardson72e344d2012-03-19 12:47:18 -0700614 data_key = &g_keyblock->data_key;
615 if (opt_verbose)
616 printf(" Signature: %s\n", signpub_key ? "valid" : "ignored");
617 printf(" Size: 0x%" PRIx64 "\n", g_keyblock->key_block_size);
618 printf(" Flags: %" PRIu64 " ", g_keyblock->key_block_flags);
619 if (g_keyblock->key_block_flags & KEY_BLOCK_FLAG_DEVELOPER_0)
Bill Richardson60bcbe32010-09-09 14:53:56 -0700620 printf(" !DEV");
Bill Richardson72e344d2012-03-19 12:47:18 -0700621 if (g_keyblock->key_block_flags & KEY_BLOCK_FLAG_DEVELOPER_1)
Bill Richardson60bcbe32010-09-09 14:53:56 -0700622 printf(" DEV");
Bill Richardson72e344d2012-03-19 12:47:18 -0700623 if (g_keyblock->key_block_flags & KEY_BLOCK_FLAG_RECOVERY_0)
Bill Richardson60bcbe32010-09-09 14:53:56 -0700624 printf(" !REC");
Bill Richardson72e344d2012-03-19 12:47:18 -0700625 if (g_keyblock->key_block_flags & KEY_BLOCK_FLAG_RECOVERY_1)
Bill Richardson60bcbe32010-09-09 14:53:56 -0700626 printf(" REC");
627 printf("\n");
Randall Spangler7d6898d2010-06-11 09:22:13 -0700628 printf(" Data key algorithm: %" PRIu64 " %s\n", data_key->algorithm,
629 (data_key->algorithm < kNumAlgorithms ?
630 algo_strings[data_key->algorithm] : "(invalid)"));
631 printf(" Data key version: %" PRIu64 "\n", data_key->key_version);
Bill Richardson60bcbe32010-09-09 14:53:56 -0700632 printf(" Data key sha1sum: ");
633 PrintPubKeySha1Sum(data_key);
634 printf("\n");
Randall Spangler7d6898d2010-06-11 09:22:13 -0700635
Bill Richardson72e344d2012-03-19 12:47:18 -0700636 if (keyblock_outfile) {
637 FILE* f = NULL;
638 f = fopen(keyblock_outfile, "wb");
639 if (!f)
640 Fatal("Can't open key block file %s\n", keyblock_outfile);
641 if (1 != fwrite(g_keyblock, g_keyblock->key_block_size, 1, f))
642 Fatal("Can't write key block file %s\n", keyblock_outfile);
643 fclose(f);
644 }
645
646 if (data_key->key_version < (min_version >> 16))
647 Fatal("Data key version %" PRIu64
Randall Spangler32a65262011-06-27 10:49:11 -0700648 " is lower than minimum %" PRIu64".\n",
649 data_key->key_version, (min_version >> 16));
Randall Spanglerae87b922011-05-12 13:27:28 -0700650
Bill Richardson72e344d2012-03-19 12:47:18 -0700651 rsa = PublicKeyToRSA(data_key);
652 if (!rsa)
653 Fatal("Error parsing data key.\n");
Randall Spangler7d6898d2010-06-11 09:22:13 -0700654
655 /* Verify preamble */
Bill Richardson72e344d2012-03-19 12:47:18 -0700656 if (0 != VerifyKernelPreamble(
657 g_preamble, g_preamble->preamble_size, rsa))
658 Fatal("Error verifying preamble.\n");
Randall Spangler7d6898d2010-06-11 09:22:13 -0700659
660 printf("Preamble:\n");
Bill Richardson72e344d2012-03-19 12:47:18 -0700661 printf(" Size: 0x%" PRIx64 "\n", g_preamble->preamble_size);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700662 printf(" Header version: %" PRIu32 ".%" PRIu32"\n",
Bill Richardson72e344d2012-03-19 12:47:18 -0700663 g_preamble->header_version_major, g_preamble->header_version_minor);
664 printf(" Kernel version: %" PRIu64 "\n", g_preamble->kernel_version);
665 printf(" Body load address: 0x%" PRIx64 "\n",
666 g_preamble->body_load_address);
Bill Richardson249677d2010-06-23 11:16:37 -0700667 printf(" Body size: 0x%" PRIx64 "\n",
Bill Richardson72e344d2012-03-19 12:47:18 -0700668 g_preamble->body_signature.data_size);
Randall Spangler87c13d82010-07-19 10:35:40 -0700669 printf(" Bootloader address: 0x%" PRIx64 "\n",
Bill Richardson72e344d2012-03-19 12:47:18 -0700670 g_preamble->bootloader_address);
671 printf(" Bootloader size: 0x%" PRIx64 "\n",
672 g_preamble->bootloader_size);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700673
Bill Richardson72e344d2012-03-19 12:47:18 -0700674 if (g_preamble->kernel_version < (min_version & 0xFFFF))
675 Fatal("Kernel version %" PRIu64 " is lower than minimum %" PRIu64 ".\n",
676 g_preamble->kernel_version, (min_version & 0xFFFF));
Randall Spanglerae87b922011-05-12 13:27:28 -0700677
Randall Spangler7d6898d2010-06-11 09:22:13 -0700678 /* Verify body */
Bill Richardson72e344d2012-03-19 12:47:18 -0700679 if (0 != VerifyData(kernel_blob, kernel_size,
680 &g_preamble->body_signature, rsa))
681 Fatal("Error verifying kernel body.\n");
Randall Spangler7d6898d2010-06-11 09:22:13 -0700682 printf("Body verification succeeded.\n");
vbendebb2b0fcc2010-07-15 15:09:47 -0700683
vbendebb2b0fcc2010-07-15 15:09:47 -0700684
Bill Richardson72e344d2012-03-19 12:47:18 -0700685 if (opt_verbose)
686 printf("Config:\n%s\n", kernel_blob + CmdLineOffset(g_preamble));
vbendebb2b0fcc2010-07-15 15:09:47 -0700687
Bill Richardson72e344d2012-03-19 12:47:18 -0700688 return 0;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700689}
690
Bill Richardson72e344d2012-03-19 12:47:18 -0700691/****************************************************************************/
Randall Spangler7d6898d2010-06-11 09:22:13 -0700692
693int main(int argc, char* argv[]) {
Randall Spangler7d6898d2010-06-11 09:22:13 -0700694 char* filename = NULL;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700695 char* oldfile = NULL;
Bill Richardson72e344d2012-03-19 12:47:18 -0700696 char* keyblock_file = NULL;
697 char* signpubkey_file = NULL;
698 char* signprivkey_file = NULL;
699 char* version_str = NULL;
vbendeb00b90882010-10-21 13:46:16 -0700700 int version = -1;
Bill Richardson72e344d2012-03-19 12:47:18 -0700701 char* vmlinuz_file = NULL;
702 char* bootloader_file = NULL;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700703 char* config_file = NULL;
Bill Richardson72e344d2012-03-19 12:47:18 -0700704 arch_t arch = ARCH_X86;
705 char *address_str = NULL;
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +0800706 uint64_t kernel_body_load_address = CROS_32BIT_ENTRY_ADDR;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700707 int mode = 0;
708 int parse_error = 0;
Randall Spanglerae87b922011-05-12 13:27:28 -0700709 uint64_t min_version = 0;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700710 char* e;
Bill Richardson72e344d2012-03-19 12:47:18 -0700711 int i;
712 VbPrivateKey* signpriv_key = NULL;
713 VbPublicKey* signpub_key = NULL;
714 uint8_t* kernel_blob = NULL;
715 uint64_t kernel_size = 0;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700716
717 char *progname = strrchr(argv[0], '/');
718 if (progname)
719 progname++;
720 else
721 progname = argv[0];
722
vbendebb2b0fcc2010-07-15 15:09:47 -0700723 while (((i = getopt_long(argc, argv, ":", long_opts, NULL)) != -1) &&
724 !parse_error) {
Randall Spangler7d6898d2010-06-11 09:22:13 -0700725 switch (i) {
Bill Richardson72e344d2012-03-19 12:47:18 -0700726 default:
727 case '?':
728 /* Unhandled option */
729 parse_error = 1;
730 break;
731
732 case 0:
733 /* silently handled option */
734 break;
735
736 case OPT_MODE_PACK:
737 case OPT_MODE_REPACK:
738 case OPT_MODE_VERIFY:
739 if (mode && (mode != i)) {
740 fprintf(stderr, "Only a single mode can be specified\n");
Randall Spangler7d6898d2010-06-11 09:22:13 -0700741 parse_error = 1;
742 break;
Bill Richardson72e344d2012-03-19 12:47:18 -0700743 }
744 mode = i;
745 filename = optarg;
746 break;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700747
Bill Richardson72e344d2012-03-19 12:47:18 -0700748 case OPT_ARCH:
749 /* check the first 3 characters to also detect x86_64 */
750 if ((!strncasecmp(optarg, "x86", 3)) ||
751 (!strcasecmp(optarg, "amd64")))
752 arch = ARCH_X86;
753 else if (!strcasecmp(optarg, "arm"))
754 arch = ARCH_ARM;
755 else {
756 fprintf(stderr, "Unknown architecture string: %s\n", optarg);
757 parse_error = 1;
758 }
759 break;
Bill Richardson4f36ef32010-08-09 17:50:14 -0700760
Bill Richardson72e344d2012-03-19 12:47:18 -0700761 case OPT_OLDBLOB:
762 oldfile = optarg;
763 break;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700764
Bill Richardson72e344d2012-03-19 12:47:18 -0700765 case OPT_KLOADADDR:
766 address_str = optarg;
767 kernel_body_load_address = strtoul(optarg, &e, 0);
768 if (!*optarg || (e && *e)) {
769 fprintf(stderr, "Invalid --kloadaddr\n");
770 parse_error = 1;
771 }
772 break;
Che-Liang Chiou03762032011-02-22 11:16:51 +0800773
Bill Richardson72e344d2012-03-19 12:47:18 -0700774 case OPT_KEYBLOCK:
775 keyblock_file = optarg;
776 break;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700777
Bill Richardson72e344d2012-03-19 12:47:18 -0700778 case OPT_SIGNPUBKEY:
779 signpubkey_file = optarg;
780 break;
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +0800781
Bill Richardson72e344d2012-03-19 12:47:18 -0700782 case OPT_SIGNPRIVATE:
783 signprivkey_file = optarg;
784 break;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700785
Bill Richardson72e344d2012-03-19 12:47:18 -0700786 case OPT_VMLINUZ:
787 vmlinuz_file = optarg;
788 break;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700789
Bill Richardson72e344d2012-03-19 12:47:18 -0700790 case OPT_BOOTLOADER:
791 bootloader_file = optarg;
792 break;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700793
Bill Richardson72e344d2012-03-19 12:47:18 -0700794 case OPT_CONFIG:
795 config_file = optarg;
796 break;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700797
Bill Richardson72e344d2012-03-19 12:47:18 -0700798 case OPT_VBLOCKONLY:
799 opt_vblockonly = 1;
800 break;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700801
Bill Richardson72e344d2012-03-19 12:47:18 -0700802 case OPT_VERSION:
803 version_str = optarg;
804 version = strtoul(optarg, &e, 0);
805 if (!*optarg || (e && *e)) {
806 fprintf(stderr, "Invalid --version\n");
807 parse_error = 1;
808 }
809 break;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700810
Bill Richardson72e344d2012-03-19 12:47:18 -0700811 case OPT_MINVERSION:
812 min_version = strtoul(optarg, &e, 0);
813 if (!*optarg || (e && *e)) {
814 fprintf(stderr, "Invalid --minversion\n");
815 parse_error = 1;
816 }
817 break;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700818
Bill Richardson72e344d2012-03-19 12:47:18 -0700819 case OPT_PAD:
820 opt_pad = strtoul(optarg, &e, 0);
821 if (!*optarg || (e && *e)) {
822 fprintf(stderr, "Invalid --pad\n");
823 parse_error = 1;
824 }
825 break;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700826 }
827 }
828
829 if (parse_error)
Bill Richardsona08b5c92010-06-30 21:59:43 -0700830 return PrintHelp(progname);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700831
832 switch(mode) {
Bill Richardson72e344d2012-03-19 12:47:18 -0700833 case OPT_MODE_PACK:
Bill Richardsona08b5c92010-06-30 21:59:43 -0700834
Bill Richardson72e344d2012-03-19 12:47:18 -0700835 /* Required */
vbendebb2b0fcc2010-07-15 15:09:47 -0700836
Bill Richardson72e344d2012-03-19 12:47:18 -0700837 if (!keyblock_file)
838 Fatal("Missing required keyblock file.\n");
Bill Richardsona08b5c92010-06-30 21:59:43 -0700839
Bill Richardson72e344d2012-03-19 12:47:18 -0700840 g_keyblock = (VbKeyBlockHeader*)ReadFile(keyblock_file, 0);
841 if (!g_keyblock)
842 Fatal("Error reading key block.\n");
Bill Richardsona08b5c92010-06-30 21:59:43 -0700843
Bill Richardson72e344d2012-03-19 12:47:18 -0700844 if (!signprivkey_file)
845 Fatal("Missing required signprivate file.\n");
846
847 signpriv_key = PrivateKeyRead(signprivkey_file);
848 if (!signpriv_key)
849 Fatal("Error reading signing key.\n");
850
851 /* Optional */
852
853 if (config_file) {
854 Debug("Reading %s\n", config_file);
855 g_config_data = ReadConfigFile(config_file, &g_config_size);
Lucian Cojocar2312ab62012-07-30 15:21:49 -0700856 if (!g_config_data)
857 Fatal("Error reading config file.\n");
Bill Richardson72e344d2012-03-19 12:47:18 -0700858 }
859
860 if (vmlinuz_file)
861 if (!ImportVmlinuzFile(vmlinuz_file, arch, kernel_body_load_address))
862 Fatal("Error reading kernel file.\n");
863
864 if (bootloader_file) {
865 Debug("Reading %s\n", bootloader_file);
866 g_bootloader_data = ReadFile(bootloader_file, &g_bootloader_size);
867 if (!g_bootloader_data)
868 Fatal("Error reading bootloader file.\n");
869 Debug(" bootloader file size=0x%" PRIx64 "\n", g_bootloader_size);
870 }
871
872 /* Do it */
873
874 kernel_blob = CreateKernelBlob(kernel_body_load_address, arch,
875 &kernel_size);
876
877 return Pack(filename, kernel_blob, kernel_size,
878 version, kernel_body_load_address,
879 signpriv_key);
880
881 case OPT_MODE_REPACK:
882
883 /* Required */
884
885 if (!signprivkey_file)
886 Fatal("Missing required signprivate file.\n");
887
888 signpriv_key = PrivateKeyRead(signprivkey_file);
889 if (!signpriv_key)
890 Fatal("Error reading signing key.\n");
891
892 if (!oldfile)
893 Fatal("Missing previously packed blob.\n");
894
895 /* Load the old blob */
896
897 kernel_blob = ReadOldBlobFromFileOrDie(oldfile, &kernel_size);
898 if (0 != Verify(kernel_blob, kernel_size, 0, 0, 0))
899 Fatal("The oldblob doesn't verify\n");
900
901 /* Take it apart */
902
903 UnpackKernelBlob(kernel_blob, kernel_size);
904 free(kernel_blob);
905
906 /* Load optional params */
907
908 if (!version_str)
909 version = g_preamble->kernel_version;
910
911 if (!address_str)
912 kernel_body_load_address = g_preamble->body_load_address;
913
914 if (config_file) {
915 if (g_config_data)
916 free(g_config_data);
917 Debug("Reading %s\n", config_file);
918 g_config_data = ReadConfigFile(config_file, &g_config_size);
Lucian Cojocar2312ab62012-07-30 15:21:49 -0700919 if (!g_config_data)
920 Fatal("Error reading config file.\n");
Bill Richardson72e344d2012-03-19 12:47:18 -0700921 }
922
923 if (keyblock_file) {
924 if (g_keyblock)
925 free(g_keyblock);
926 g_keyblock = (VbKeyBlockHeader*)ReadFile(keyblock_file, 0);
927 if (!g_keyblock)
928 Fatal("Error reading key block.\n");
929 }
930
931 /* Put it back together */
932
933 kernel_blob = CreateKernelBlob(kernel_body_load_address, arch,
934 &kernel_size);
935
936 return Pack(filename, kernel_blob, kernel_size,
937 version, kernel_body_load_address,
938 signpriv_key);
939
940
941 case OPT_MODE_VERIFY:
942
943 /* Optional */
944
945 if (signpubkey_file) {
946 signpub_key = PublicKeyRead(signpubkey_file);
947 if (!signpub_key)
948 Fatal("Error reading public key.\n");
949 }
950
951 /* Do it */
952
953 kernel_blob = ReadOldBlobFromFileOrDie(filename, &kernel_size);
954
955 return Verify(kernel_blob, kernel_size, signpub_key,
956 keyblock_file, min_version);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700957 }
Bill Richardson72e344d2012-03-19 12:47:18 -0700958
959 fprintf(stderr, "You must specify a mode: --pack, --repack or --verify\n");
960 return PrintHelp(progname);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700961}