blob: 24a2ba6cdb11f9d5a0e59428892dab33d99dc44d [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,
Gaurav Shah36ba3402014-05-14 17:28:27 -070058 ARCH_X86, /* default */
59 ARCH_MIPS
Bill Richardson72e344d2012-03-19 12:47:18 -070060} arch_t;
Che-Liang Chiou03762032011-02-22 11:16:51 +080061
Randall Spangler7d6898d2010-06-11 09:22:13 -070062static struct option long_opts[] = {
63 {"pack", 1, 0, OPT_MODE_PACK },
Bill Richardsona08b5c92010-06-30 21:59:43 -070064 {"repack", 1, 0, OPT_MODE_REPACK },
Randall Spangler7d6898d2010-06-11 09:22:13 -070065 {"verify", 1, 0, OPT_MODE_VERIFY },
Che-Liang Chiou03762032011-02-22 11:16:51 +080066 {"arch", 1, 0, OPT_ARCH },
Bill Richardsona08b5c92010-06-30 21:59:43 -070067 {"oldblob", 1, 0, OPT_OLDBLOB },
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +080068 {"kloadaddr", 1, 0, OPT_KLOADADDR },
Randall Spangler7d6898d2010-06-11 09:22:13 -070069 {"keyblock", 1, 0, OPT_KEYBLOCK },
70 {"signpubkey", 1, 0, OPT_SIGNPUBKEY },
71 {"signprivate", 1, 0, OPT_SIGNPRIVATE },
72 {"version", 1, 0, OPT_VERSION },
Randall Spanglerae87b922011-05-12 13:27:28 -070073 {"minversion", 1, 0, OPT_MINVERSION },
Randall Spangler7d6898d2010-06-11 09:22:13 -070074 {"vmlinuz", 1, 0, OPT_VMLINUZ },
75 {"bootloader", 1, 0, OPT_BOOTLOADER },
76 {"config", 1, 0, OPT_CONFIG },
Bill Richardsona08b5c92010-06-30 21:59:43 -070077 {"vblockonly", 0, 0, OPT_VBLOCKONLY },
Randall Spangler7d6898d2010-06-11 09:22:13 -070078 {"pad", 1, 0, OPT_PAD },
Bill Richardson72e344d2012-03-19 12:47:18 -070079 {"verbose", 0, &opt_verbose, 1 },
Bill Richardson249677d2010-06-23 11:16:37 -070080 {"debug", 0, &opt_debug, 1 },
Randall Spangler7d6898d2010-06-11 09:22:13 -070081 {NULL, 0, 0, 0}
82};
83
84
85/* Print help and return error */
Bill Richardsona08b5c92010-06-30 21:59:43 -070086static int PrintHelp(char *progname) {
87 fprintf(stderr,
88 "This program creates, signs, and verifies the kernel blob\n");
89 fprintf(stderr,
90 "\n"
91 "Usage: %s --pack <file> [PARAMETERS]\n"
92 "\n"
93 " Required parameters:\n"
94 " --keyblock <file> Key block in .keyblock format\n"
Bill Richardson72e344d2012-03-19 12:47:18 -070095 " --signprivate <file> Private key to sign kernel data,\n"
96 " in .vbprivk format\n"
Bill Richardsona08b5c92010-06-30 21:59:43 -070097 " --version <number> Kernel version\n"
98 " --vmlinuz <file> Linux kernel bzImage file\n"
99 " --bootloader <file> Bootloader stub\n"
vbendebb2b0fcc2010-07-15 15:09:47 -0700100 " --config <file> Command line file\n"
Che-Liang Chiou03762032011-02-22 11:16:51 +0800101 " --arch <arch> Cpu architecture (default x86)\n"
Bill Richardsona08b5c92010-06-30 21:59:43 -0700102 "\n"
103 " Optional:\n"
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +0800104 " --kloadaddr <address> Assign kernel body load address\n"
Bill Richardsona08b5c92010-06-30 21:59:43 -0700105 " --pad <number> Verification padding size in bytes\n"
106 " --vblockonly Emit just the verification blob\n",
107 progname);
108 fprintf(stderr,
109 "\nOR\n\n"
110 "Usage: %s --repack <file> [PARAMETERS]\n"
111 "\n"
Bill Richardson72e344d2012-03-19 12:47:18 -0700112 " Required parameters:\n"
113 " --signprivate <file> Private key to sign kernel data,\n"
114 " in .vbprivk format\n"
Bill Richardsona08b5c92010-06-30 21:59:43 -0700115 " --oldblob <file> Previously packed kernel blob\n"
Bill Richardson72e344d2012-03-19 12:47:18 -0700116 " (including verfication blob)\n"
Bill Richardsona08b5c92010-06-30 21:59:43 -0700117 "\n"
118 " Optional:\n"
Bill Richardson72e344d2012-03-19 12:47:18 -0700119 " --keyblock <file> Key block in .keyblock format\n"
120 " --config <file> New command line file\n"
121 " --version <number> Kernel version\n"
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +0800122 " --kloadaddr <address> Assign kernel body load address\n"
Bill Richardson72e344d2012-03-19 12:47:18 -0700123 " --pad <number> Verification blob size in bytes\n"
Bill Richardsona08b5c92010-06-30 21:59:43 -0700124 " --vblockonly Emit just the verification blob\n",
125 progname);
126 fprintf(stderr,
127 "\nOR\n\n"
128 "Usage: %s --verify <file> [PARAMETERS]\n"
129 "\n"
vbendebb2b0fcc2010-07-15 15:09:47 -0700130 " Optional:\n"
Bill Richardson4f36ef32010-08-09 17:50:14 -0700131 " --signpubkey <file>"
Bill Richardson72e344d2012-03-19 12:47:18 -0700132 " Public key to verify kernel keyblock,\n"
133 " in .vbpubk format\n"
vbendebb2b0fcc2010-07-15 15:09:47 -0700134 " --verbose Print a more detailed report\n"
Bill Richardson72e344d2012-03-19 12:47:18 -0700135 " --keyblock <file> Outputs the verified key block,\n"
136 " in .keyblock format\n"
Randall Spangler7ecb39d2011-05-12 15:37:45 -0700137 " --pad <number> Verification padding size in bytes\n"
Randall Spanglerae87b922011-05-12 13:27:28 -0700138 " --minversion <number> Minimum combined kernel key version\n"
139 " and kernel version\n"
Bill Richardsona08b5c92010-06-30 21:59:43 -0700140 "\n",
141 progname);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700142 return 1;
143}
144
Bill Richardson249677d2010-06-23 11:16:37 -0700145static void Debug(const char *format, ...) {
146 if (!opt_debug)
147 return;
148
149 va_list ap;
150 va_start(ap, format);
151 fprintf(stderr, "DEBUG: ");
152 vfprintf(stderr, format, ap);
153 va_end(ap);
154}
155
Bill Richardson72e344d2012-03-19 12:47:18 -0700156static void Fatal(const char *format, ...) {
157 va_list ap;
158 va_start(ap, format);
159 fprintf(stderr, "ERROR: ");
160 vfprintf(stderr, format, ap);
161 va_end(ap);
162 exit(1);
163}
164
Bill Richardson2f6a71f2010-10-14 09:25:39 -0700165/* Return an explanation when fread() fails. */
166static const char *error_fread(FILE *fp) {
167 const char *retval = "beats me why";
168 if (feof(fp))
169 retval = "EOF";
170 else if (ferror(fp))
171 retval = strerror(errno);
172 clearerr(fp);
173 return retval;
174}
Randall Spangler7d6898d2010-06-11 09:22:13 -0700175
176/* Return the smallest integral multiple of [alignment] that is equal
177 * to or greater than [val]. Used to determine the number of
178 * pages/sectors/blocks/whatever needed to contain [val]
179 * items/bytes/etc. */
180static uint64_t roundup(uint64_t val, uint64_t alignment) {
181 uint64_t rem = val % alignment;
182 if ( rem )
183 return val + (alignment - rem);
184 return val;
185}
186
187
188/* Match regexp /\b--\b/ to delimit the start of the kernel commandline. If we
189 * don't find one, we'll use the whole thing. */
190static unsigned int find_cmdline_start(char *input, unsigned int max_len) {
191 int start = 0;
192 int i;
193 for(i = 0; i < max_len - 1 && input[i]; i++) {
194 if ('-' == input[i] && '-' == input[i + 1]) { /* found a "--" */
195 if ((i == 0 || ' ' == input[i - 1]) && /* nothing before it */
196 (i + 2 >= max_len || ' ' == input[i+2])) { /* nothing after it */
197 start = i+2; /* note: hope there's a trailing '\0' */
198 break;
199 }
200 }
201 }
202 while(' ' == input[start]) /* skip leading spaces */
203 start++;
204
205 return start;
206}
207
208
Bill Richardson72e344d2012-03-19 12:47:18 -0700209/****************************************************************************/
210/* Here are globals containing all the bits & pieces I'm working on. */
211
212/* The individual parts that go into the kernel blob */
213uint8_t *g_kernel_data;
214uint64_t g_kernel_size;
215uint8_t *g_param_data;
216uint64_t g_param_size;
217uint8_t *g_config_data;
218uint64_t g_config_size;
219uint8_t *g_bootloader_data;
220uint64_t g_bootloader_size;
221uint64_t g_bootloader_address;
Bill Richardsonc8b9ca62012-03-14 10:54:05 -0700222
223
Bill Richardson72e344d2012-03-19 12:47:18 -0700224/* The individual parts of the verification blob (including the data that
225 * immediately follows the headers) */
226VbKeyBlockHeader* g_keyblock;
227VbKernelPreambleHeader* g_preamble;
vbendebb2b0fcc2010-07-15 15:09:47 -0700228
Bill Richardson72e344d2012-03-19 12:47:18 -0700229/****************************************************************************/
Bill Richardsona08b5c92010-06-30 21:59:43 -0700230
vbendebb2b0fcc2010-07-15 15:09:47 -0700231/*
232 * Read the kernel command line from a file. Get rid of \n characters along
233 * the way and verify that the line fits into a 4K buffer.
234 *
235 * Return the buffer contaning the line on success (and set the line length
236 * using the passed in parameter), or NULL in case something goes wrong.
237 */
238static uint8_t* ReadConfigFile(const char* config_file, uint64_t* config_size)
239{
240 uint8_t* config_buf;
241 int ii;
242
243 config_buf = ReadFile(config_file, config_size);
244 Debug(" config file size=0x%" PRIx64 "\n", *config_size);
245 if (CROS_CONFIG_SIZE <= *config_size) { /* need room for trailing '\0' */
Randall Spangler32a65262011-06-27 10:49:11 -0700246 VbExError("Config file %s is too large (>= %d bytes)\n",
247 config_file, CROS_CONFIG_SIZE);
vbendebb2b0fcc2010-07-15 15:09:47 -0700248 return NULL;
249 }
250
251 /* Replace newlines with spaces */
252 for (ii = 0; ii < *config_size; ii++) {
253 if ('\n' == config_buf[ii]) {
254 config_buf[ii] = ' ';
255 }
256 }
257 return config_buf;
258}
259
Bill Richardson72e344d2012-03-19 12:47:18 -0700260
261/* Offset of kernel command line string from start of packed kernel blob */
262static uint64_t CmdLineOffset(VbKernelPreambleHeader *preamble) {
263 return preamble->bootloader_address - preamble->body_load_address -
264 CROS_CONFIG_SIZE - CROS_PARAMS_SIZE;
265}
266
267/* This initializes g_vmlinuz and g_param from a standard vmlinuz file.
268 * It returns 0 on error. */
269static int ImportVmlinuzFile(const char *vmlinuz_file, arch_t arch,
270 uint64_t kernel_body_load_address) {
271 uint8_t *kernel_buf;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700272 uint64_t kernel_size;
273 uint64_t kernel32_start = 0;
274 uint64_t kernel32_size = 0;
Kees Cooke0e4ed42013-04-10 18:05:51 -0700275 struct linux_kernel_params *params = NULL, *lh = NULL;
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. */
Kees Cooke0e4ed42013-04-10 18:05:51 -0700301 lh = (struct linux_kernel_params *)kernel_buf;
Bill Richardson72e344d2012-03-19 12:47:18 -0700302 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),
Kees Cooke0e4ed42013-04-10 18:05:51 -0700321 offsetof(struct linux_kernel_params, e820_entries)
322 - offsetof(struct linux_kernel_params, setup_sects));
Randall Spangler7d6898d2010-06-11 09:22:13 -0700323 params->boot_flag = 0;
Bill Richardson72e344d2012-03-19 12:47:18 -0700324 params->ramdisk_image = 0; /* we don't support initrd */
Randall Spangler7d6898d2010-06-11 09:22:13 -0700325 params->ramdisk_size = 0;
326 params->type_of_loader = 0xff;
Bill Richardson72e344d2012-03-19 12:47:18 -0700327 /* We need to point to the kernel commandline arg. On disk, it will come
328 * right after the 32-bit part of the kernel. */
329 params->cmd_line_ptr = kernel_body_load_address +
330 roundup(kernel32_size, CROS_ALIGN) +
331 find_cmdline_start((char *)g_config_data, g_config_size);
332 Debug(" cmdline_addr=0x%x\n", params->cmd_line_ptr);
Kees Cooke0e4ed42013-04-10 18:05:51 -0700333 Debug(" version=0x%x\n", params->version);
334 Debug(" kernel_alignment=0x%x\n", params->kernel_alignment);
335 Debug(" relocatable_kernel=0x%x\n", params->relocatable_kernel);
Che-Liang Chiou475bf442010-08-23 11:20:44 +0800336 /* A fake e820 memory map with 2 entries */
337 params->n_e820_entry = 2;
338 params->e820_entries[0].start_addr = 0x00000000;
339 params->e820_entries[0].segment_size = 0x00001000;
340 params->e820_entries[0].segment_type = E820_TYPE_RAM;
341 params->e820_entries[1].start_addr = 0xfffff000;
342 params->e820_entries[1].segment_size = 0x00001000;
343 params->e820_entries[1].segment_type = E820_TYPE_RESERVED;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700344
Bill Richardson72e344d2012-03-19 12:47:18 -0700345 /* done */
Randall Spangler32a65262011-06-27 10:49:11 -0700346 free(kernel_buf);
Bill Richardson72e344d2012-03-19 12:47:18 -0700347 return 1;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700348}
349
Bill Richardson72e344d2012-03-19 12:47:18 -0700350/* This returns just the kernel blob, with the verification blob separated
351 * and copied to new memory in g_keyblock and g_preamble. */
352static uint8_t* ReadOldBlobFromFileOrDie(const char *filename,
353 uint64_t* size_ptr) {
vbendebb2b0fcc2010-07-15 15:09:47 -0700354 FILE* fp = NULL;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700355 struct stat statbuf;
356 VbKeyBlockHeader* key_block;
357 VbKernelPreambleHeader* preamble;
358 uint64_t now = 0;
Bill Richardson72e344d2012-03-19 12:47:18 -0700359 uint8_t* buf;
360 uint8_t* kernel_blob_data;
361 uint64_t kernel_blob_size;
Vincent Palatin56c85db2012-09-05 15:35:12 -0700362 uint64_t file_size = 0;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700363
Bill Richardson72e344d2012-03-19 12:47:18 -0700364 if (0 != stat(filename, &statbuf))
365 Fatal("Unable to stat %s: %s\n", filename, strerror(errno));
Bill Richardsona08b5c92010-06-30 21:59:43 -0700366
Vincent Palatin56c85db2012-09-05 15:35:12 -0700367 if (S_ISBLK(statbuf.st_mode)) {
368 int fd;
369
370 if ((fd = open(filename, O_RDONLY)) >= 0) {
371 ioctl(fd, BLKGETSIZE64, &file_size);
372 close(fd);
373 }
374 } else {
375 file_size = statbuf.st_size;
376 }
377 Debug("%s size is 0x%" PRIx64 "\n", filename, file_size);
378 if (file_size < opt_pad)
Bill Richardson72e344d2012-03-19 12:47:18 -0700379 Fatal("%s is too small to be a valid kernel blob\n");
Bill Richardsona08b5c92010-06-30 21:59:43 -0700380
381 Debug("Reading %s\n", filename);
382 fp = fopen(filename, "rb");
Bill Richardson72e344d2012-03-19 12:47:18 -0700383 if (!fp)
384 Fatal("Unable to open file %s: %s\n", filename, strerror(errno));
Bill Richardsona08b5c92010-06-30 21:59:43 -0700385
Bill Richardson72e344d2012-03-19 12:47:18 -0700386 buf = VbExMalloc(opt_pad);
387 if (1 != fread(buf, opt_pad, 1, fp))
388 Fatal("Unable to read header from %s: %s\n", filename, error_fread(fp));
vbendebb2b0fcc2010-07-15 15:09:47 -0700389
Bill Richardson72e344d2012-03-19 12:47:18 -0700390 /* Sanity-check the key_block */
Bill Richardsona08b5c92010-06-30 21:59:43 -0700391 key_block = (VbKeyBlockHeader*)buf;
392 Debug("Keyblock is 0x%" PRIx64 " bytes\n", key_block->key_block_size);
393 now += key_block->key_block_size;
Vincent Palatin56c85db2012-09-05 15:35:12 -0700394 if (now > file_size)
Bill Richardson72e344d2012-03-19 12:47:18 -0700395 Fatal("key_block_size advances past the end of the blob\n");
396 if (now > opt_pad)
397 Fatal("key_block_size advances past %" PRIu64 " byte padding\n",
398 opt_pad);
399 /* LGTM */
400 g_keyblock = (VbKeyBlockHeader*)VbExMalloc(key_block->key_block_size);
401 Memcpy(g_keyblock, key_block, key_block->key_block_size);
Bill Richardsona08b5c92010-06-30 21:59:43 -0700402
Bill Richardson72e344d2012-03-19 12:47:18 -0700403 /* And the preamble */
Bill Richardsona08b5c92010-06-30 21:59:43 -0700404 preamble = (VbKernelPreambleHeader*)(buf + now);
405 Debug("Preamble is 0x%" PRIx64 " bytes\n", preamble->preamble_size);
406 now += preamble->preamble_size;
Vincent Palatin56c85db2012-09-05 15:35:12 -0700407 if (now > file_size)
Bill Richardson72e344d2012-03-19 12:47:18 -0700408 Fatal("preamble_size advances past the end of the blob\n");
409 if (now > opt_pad)
410 Fatal("preamble_size advances past %" PRIu64 " byte padding\n",
411 opt_pad);
412 /* LGTM */
413 Debug(" kernel_version = %d\n", preamble->kernel_version);
414 Debug(" bootloader_address = 0x%" PRIx64 "\n", preamble->bootloader_address);
415 Debug(" bootloader_size = 0x%" PRIx64 "\n", preamble->bootloader_size);
416 Debug(" kern_blob_size = 0x%" PRIx64 "\n",
417 preamble->body_signature.data_size);
418 g_preamble = (VbKernelPreambleHeader*)VbExMalloc(preamble->preamble_size);
419 Memcpy(g_preamble, preamble, preamble->preamble_size);
Bill Richardsona08b5c92010-06-30 21:59:43 -0700420
Bill Richardson72e344d2012-03-19 12:47:18 -0700421 /* Now for the kernel blob */
Bill Richardsona08b5c92010-06-30 21:59:43 -0700422 Debug("kernel blob is at offset 0x%" PRIx64 "\n", now);
Bill Richardson72e344d2012-03-19 12:47:18 -0700423 if (0 != fseek(fp, now, SEEK_SET))
424 Fatal("Unable to seek to 0x%" PRIx64 " in %s: %s\n", now, filename,
Bill Richardsona08b5c92010-06-30 21:59:43 -0700425 strerror(errno));
Bill Richardsona08b5c92010-06-30 21:59:43 -0700426
Bill Richardson72e344d2012-03-19 12:47:18 -0700427 /* Sanity check */
Vincent Palatin56c85db2012-09-05 15:35:12 -0700428 kernel_blob_size = file_size - now;
Bill Richardson72e344d2012-03-19 12:47:18 -0700429 if (!kernel_blob_size)
430 Fatal("No kernel blob found\n");
431 if (kernel_blob_size < preamble->body_signature.data_size)
432 fprintf(stderr, "Warning: kernel file only has 0x%" PRIx64 " bytes\n",
433 kernel_blob_size);
434 kernel_blob_data = VbExMalloc(kernel_blob_size);
Bill Richardsona08b5c92010-06-30 21:59:43 -0700435
Bill Richardson72e344d2012-03-19 12:47:18 -0700436 /* Read it in */
437 if (1 != fread(kernel_blob_data, kernel_blob_size, 1, fp))
438 Fatal("Unable to read kernel blob from %s: %s\n", filename,
Randall Spangler32a65262011-06-27 10:49:11 -0700439 error_fread(fp));
Bill Richardsona08b5c92010-06-30 21:59:43 -0700440
Bill Richardson72e344d2012-03-19 12:47:18 -0700441 /* Done */
442 VbExFree(buf);
Bill Richardsona08b5c92010-06-30 21:59:43 -0700443
Bill Richardson72e344d2012-03-19 12:47:18 -0700444 if (size_ptr)
445 *size_ptr = kernel_blob_size;
446
447 return kernel_blob_data;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700448}
449
450
Bill Richardson72e344d2012-03-19 12:47:18 -0700451/* Split a kernel blob into separate g_kernel, g_param, g_config, and
452 * g_bootloader parts. */
453static void UnpackKernelBlob(uint8_t *kernel_blob_data,
454 uint64_t kernel_blob_size) {
455
456 uint64_t k_blob_size = g_preamble->body_signature.data_size;
457 uint64_t k_blob_ofs = 0;
458 uint64_t b_size = g_preamble->bootloader_size;
459 uint64_t b_ofs = k_blob_ofs + g_preamble->bootloader_address -
460 g_preamble->body_load_address;
461 uint64_t p_ofs = b_ofs - CROS_CONFIG_SIZE;
462 uint64_t c_ofs = p_ofs - CROS_PARAMS_SIZE;
Bill Richardson72e344d2012-03-19 12:47:18 -0700463
464 Debug("k_blob_size = 0x%" PRIx64 "\n", k_blob_size );
465 Debug("k_blob_ofs = 0x%" PRIx64 "\n", k_blob_ofs );
466 Debug("b_size = 0x%" PRIx64 "\n", b_size );
467 Debug("b_ofs = 0x%" PRIx64 "\n", b_ofs );
468 Debug("p_ofs = 0x%" PRIx64 "\n", p_ofs );
469 Debug("c_ofs = 0x%" PRIx64 "\n", c_ofs );
470
471 g_kernel_size = c_ofs;
472 g_kernel_data = VbExMalloc(g_kernel_size);
473 Memcpy(g_kernel_data, kernel_blob_data, g_kernel_size);
474
475 g_param_size = CROS_PARAMS_SIZE;
476 g_param_data = VbExMalloc(g_param_size);
477 Memcpy(g_param_data, kernel_blob_data + p_ofs, g_param_size);
478
479 g_config_size = CROS_CONFIG_SIZE;
480 g_config_data = VbExMalloc(g_config_size);
481 Memcpy(g_config_data, kernel_blob_data + c_ofs, g_config_size);
482
483 g_bootloader_size = b_size;
484 g_bootloader_data = VbExMalloc(g_bootloader_size);
485 Memcpy(g_bootloader_data, kernel_blob_data + b_ofs, g_bootloader_size);
486}
487
488
489
490/****************************************************************************/
491
492static uint8_t* CreateKernelBlob(uint64_t kernel_body_load_address,
493 arch_t arch,
494 uint64_t *size_ptr) {
495 uint8_t *kern_blob;
496 uint64_t kern_blob_size;
497 uint64_t now;
498 uint64_t bootloader_size = roundup(g_bootloader_size, CROS_ALIGN);
499
500 /* Put the kernel blob together */
501 kern_blob_size = roundup(g_kernel_size, CROS_ALIGN) +
502 CROS_CONFIG_SIZE + CROS_PARAMS_SIZE + bootloader_size;
503 Debug("kern_blob_size=0x%" PRIx64 "\n", kern_blob_size);
504 kern_blob = VbExMalloc(kern_blob_size);
505 Memset(kern_blob, 0, kern_blob_size);
506 now = 0;
507
508 Debug("kernel goes at kern_blob+0x%" PRIx64 "\n", now);
509
510 Memcpy(kern_blob+now, g_kernel_data, g_kernel_size);
511 now += roundup(g_kernel_size, CROS_ALIGN);
512
513 Debug("config goes at kern_blob+0x%" PRIx64 "\n", now);
514 if (g_config_size)
515 Memcpy(kern_blob + now, g_config_data, g_config_size);
516 now += CROS_CONFIG_SIZE;
517
518 Debug("params goes at kern_blob+0x%" PRIx64 "\n", now);
519 if (g_param_size) {
520 Memcpy(kern_blob + now, g_param_data, g_param_size);
521 }
522 now += CROS_PARAMS_SIZE;
523
524 Debug("bootloader goes at kern_blob+0x%" PRIx64 "\n", now);
525 g_bootloader_address = kernel_body_load_address + now;
526 Debug(" bootloader_address=0x%" PRIx64 "\n", g_bootloader_address);
527 Debug(" bootloader_size=0x%" PRIx64 "\n", bootloader_size);
528 if (bootloader_size)
529 Memcpy(kern_blob + now, g_bootloader_data, g_bootloader_size);
530 now += bootloader_size;
531 Debug("end of kern_blob at kern_blob+0x%" PRIx64 "\n", now);
532
533 /* Done */
534 if (size_ptr)
535 *size_ptr = kern_blob_size;
536
537 return kern_blob;
538}
539
540static int Pack(const char* outfile,
541 uint8_t *kernel_blob,
542 uint64_t kernel_size,
543 int version,
544 uint64_t kernel_body_load_address,
545 VbPrivateKey* signpriv_key) {
Bill Richardsona08b5c92010-06-30 21:59:43 -0700546 VbSignature* body_sig;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700547 FILE* f;
548 uint64_t i;
Bill Richardsonc8b9ca62012-03-14 10:54:05 -0700549 uint64_t written = 0;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700550
Randall Spangler7d6898d2010-06-11 09:22:13 -0700551 /* Sign the kernel data */
Bill Richardson72e344d2012-03-19 12:47:18 -0700552 body_sig = CalculateSignature(kernel_blob, kernel_size, signpriv_key);
553 if (!body_sig)
554 Fatal("Error calculating body signature\n");
Randall Spangler7d6898d2010-06-11 09:22:13 -0700555
556 /* Create preamble */
Bill Richardson72e344d2012-03-19 12:47:18 -0700557 g_preamble = CreateKernelPreamble(version,
558 kernel_body_load_address,
559 g_bootloader_address,
560 roundup(g_bootloader_size, CROS_ALIGN),
561 body_sig,
562 opt_pad - g_keyblock->key_block_size,
563 signpriv_key);
564 if (!g_preamble) {
Randall Spangler32a65262011-06-27 10:49:11 -0700565 VbExError("Error creating preamble.\n");
Randall Spangler7d6898d2010-06-11 09:22:13 -0700566 return 1;
567 }
Randall Spangler7d6898d2010-06-11 09:22:13 -0700568 /* Write the output file */
Bill Richardson249677d2010-06-23 11:16:37 -0700569 Debug("writing %s...\n", outfile);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700570 f = fopen(outfile, "wb");
571 if (!f) {
Randall Spangler32a65262011-06-27 10:49:11 -0700572 VbExError("Can't open output file %s\n", outfile);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700573 return 1;
574 }
Bill Richardson72e344d2012-03-19 12:47:18 -0700575 Debug("0x%" PRIx64 " bytes of key_block\n", g_keyblock->key_block_size);
576 Debug("0x%" PRIx64 " bytes of preamble\n", g_preamble->preamble_size);
577 i = ((1 != fwrite(g_keyblock, g_keyblock->key_block_size, 1, f)) ||
578 (1 != fwrite(g_preamble, g_preamble->preamble_size, 1, f)));
Randall Spangler7d6898d2010-06-11 09:22:13 -0700579 if (i) {
Randall Spangler32a65262011-06-27 10:49:11 -0700580 VbExError("Can't write output file %s\n", outfile);
Bill Richardsona08b5c92010-06-30 21:59:43 -0700581 fclose(f);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700582 unlink(outfile);
583 return 1;
584 }
Bill Richardson72e344d2012-03-19 12:47:18 -0700585 written += g_keyblock->key_block_size;
586 written += g_preamble->preamble_size;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700587
Bill Richardson72e344d2012-03-19 12:47:18 -0700588 if (!opt_vblockonly) {
589 Debug("0x%" PRIx64 " bytes of kern_blob\n", kernel_size);
590 i = (1 != fwrite(kernel_blob, kernel_size, 1, f));
Bill Richardsona08b5c92010-06-30 21:59:43 -0700591 if (i) {
Bill Richardsona08b5c92010-06-30 21:59:43 -0700592 fclose(f);
593 unlink(outfile);
Bill Richardson72e344d2012-03-19 12:47:18 -0700594 Fatal("Can't write output file %s\n", outfile);
Bill Richardsona08b5c92010-06-30 21:59:43 -0700595 }
Bill Richardson72e344d2012-03-19 12:47:18 -0700596 written += kernel_size;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700597 }
Bill Richardsonc8b9ca62012-03-14 10:54:05 -0700598 Debug("0x%" PRIx64 " bytes total\n", written);
Bill Richardsona08b5c92010-06-30 21:59:43 -0700599 fclose(f);
600
Randall Spangler7d6898d2010-06-11 09:22:13 -0700601 /* Success */
602 return 0;
603}
604
Bill Richardson72e344d2012-03-19 12:47:18 -0700605static int Verify(uint8_t* kernel_blob,
606 uint64_t kernel_size,
607 VbPublicKey* signpub_key,
608 const char* keyblock_outfile,
609 uint64_t min_version) {
Randall Spangler7d6898d2010-06-11 09:22:13 -0700610 VbPublicKey* data_key;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700611 RSAPublicKey* rsa;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700612
Bill Richardson72e344d2012-03-19 12:47:18 -0700613 if (0 != KeyBlockVerify(g_keyblock, g_keyblock->key_block_size,
614 signpub_key, (0 == signpub_key)))
615 Fatal("Error verifying key block.\n");
Will Drewry9342f882010-10-26 10:22:05 -0500616
Randall Spangler7d6898d2010-06-11 09:22:13 -0700617 printf("Key block:\n");
Bill Richardson72e344d2012-03-19 12:47:18 -0700618 data_key = &g_keyblock->data_key;
619 if (opt_verbose)
620 printf(" Signature: %s\n", signpub_key ? "valid" : "ignored");
621 printf(" Size: 0x%" PRIx64 "\n", g_keyblock->key_block_size);
622 printf(" Flags: %" PRIu64 " ", g_keyblock->key_block_flags);
623 if (g_keyblock->key_block_flags & KEY_BLOCK_FLAG_DEVELOPER_0)
Bill Richardson60bcbe32010-09-09 14:53:56 -0700624 printf(" !DEV");
Bill Richardson72e344d2012-03-19 12:47:18 -0700625 if (g_keyblock->key_block_flags & KEY_BLOCK_FLAG_DEVELOPER_1)
Bill Richardson60bcbe32010-09-09 14:53:56 -0700626 printf(" DEV");
Bill Richardson72e344d2012-03-19 12:47:18 -0700627 if (g_keyblock->key_block_flags & KEY_BLOCK_FLAG_RECOVERY_0)
Bill Richardson60bcbe32010-09-09 14:53:56 -0700628 printf(" !REC");
Bill Richardson72e344d2012-03-19 12:47:18 -0700629 if (g_keyblock->key_block_flags & KEY_BLOCK_FLAG_RECOVERY_1)
Bill Richardson60bcbe32010-09-09 14:53:56 -0700630 printf(" REC");
631 printf("\n");
Randall Spangler7d6898d2010-06-11 09:22:13 -0700632 printf(" Data key algorithm: %" PRIu64 " %s\n", data_key->algorithm,
633 (data_key->algorithm < kNumAlgorithms ?
634 algo_strings[data_key->algorithm] : "(invalid)"));
635 printf(" Data key version: %" PRIu64 "\n", data_key->key_version);
Bill Richardson60bcbe32010-09-09 14:53:56 -0700636 printf(" Data key sha1sum: ");
637 PrintPubKeySha1Sum(data_key);
638 printf("\n");
Randall Spangler7d6898d2010-06-11 09:22:13 -0700639
Bill Richardson72e344d2012-03-19 12:47:18 -0700640 if (keyblock_outfile) {
641 FILE* f = NULL;
642 f = fopen(keyblock_outfile, "wb");
643 if (!f)
644 Fatal("Can't open key block file %s\n", keyblock_outfile);
645 if (1 != fwrite(g_keyblock, g_keyblock->key_block_size, 1, f))
646 Fatal("Can't write key block file %s\n", keyblock_outfile);
647 fclose(f);
648 }
649
650 if (data_key->key_version < (min_version >> 16))
651 Fatal("Data key version %" PRIu64
Randall Spangler32a65262011-06-27 10:49:11 -0700652 " is lower than minimum %" PRIu64".\n",
653 data_key->key_version, (min_version >> 16));
Randall Spanglerae87b922011-05-12 13:27:28 -0700654
Bill Richardson72e344d2012-03-19 12:47:18 -0700655 rsa = PublicKeyToRSA(data_key);
656 if (!rsa)
657 Fatal("Error parsing data key.\n");
Randall Spangler7d6898d2010-06-11 09:22:13 -0700658
659 /* Verify preamble */
Bill Richardson72e344d2012-03-19 12:47:18 -0700660 if (0 != VerifyKernelPreamble(
661 g_preamble, g_preamble->preamble_size, rsa))
662 Fatal("Error verifying preamble.\n");
Randall Spangler7d6898d2010-06-11 09:22:13 -0700663
664 printf("Preamble:\n");
Bill Richardson72e344d2012-03-19 12:47:18 -0700665 printf(" Size: 0x%" PRIx64 "\n", g_preamble->preamble_size);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700666 printf(" Header version: %" PRIu32 ".%" PRIu32"\n",
Bill Richardson72e344d2012-03-19 12:47:18 -0700667 g_preamble->header_version_major, g_preamble->header_version_minor);
668 printf(" Kernel version: %" PRIu64 "\n", g_preamble->kernel_version);
669 printf(" Body load address: 0x%" PRIx64 "\n",
670 g_preamble->body_load_address);
Bill Richardson249677d2010-06-23 11:16:37 -0700671 printf(" Body size: 0x%" PRIx64 "\n",
Bill Richardson72e344d2012-03-19 12:47:18 -0700672 g_preamble->body_signature.data_size);
Randall Spangler87c13d82010-07-19 10:35:40 -0700673 printf(" Bootloader address: 0x%" PRIx64 "\n",
Bill Richardson72e344d2012-03-19 12:47:18 -0700674 g_preamble->bootloader_address);
675 printf(" Bootloader size: 0x%" PRIx64 "\n",
676 g_preamble->bootloader_size);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700677
Bill Richardson72e344d2012-03-19 12:47:18 -0700678 if (g_preamble->kernel_version < (min_version & 0xFFFF))
679 Fatal("Kernel version %" PRIu64 " is lower than minimum %" PRIu64 ".\n",
680 g_preamble->kernel_version, (min_version & 0xFFFF));
Randall Spanglerae87b922011-05-12 13:27:28 -0700681
Randall Spangler7d6898d2010-06-11 09:22:13 -0700682 /* Verify body */
Bill Richardson72e344d2012-03-19 12:47:18 -0700683 if (0 != VerifyData(kernel_blob, kernel_size,
684 &g_preamble->body_signature, rsa))
685 Fatal("Error verifying kernel body.\n");
Randall Spangler7d6898d2010-06-11 09:22:13 -0700686 printf("Body verification succeeded.\n");
vbendebb2b0fcc2010-07-15 15:09:47 -0700687
vbendebb2b0fcc2010-07-15 15:09:47 -0700688
Bill Richardson72e344d2012-03-19 12:47:18 -0700689 if (opt_verbose)
690 printf("Config:\n%s\n", kernel_blob + CmdLineOffset(g_preamble));
vbendebb2b0fcc2010-07-15 15:09:47 -0700691
Bill Richardson72e344d2012-03-19 12:47:18 -0700692 return 0;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700693}
694
Bill Richardson72e344d2012-03-19 12:47:18 -0700695/****************************************************************************/
Randall Spangler7d6898d2010-06-11 09:22:13 -0700696
697int main(int argc, char* argv[]) {
Randall Spangler7d6898d2010-06-11 09:22:13 -0700698 char* filename = NULL;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700699 char* oldfile = NULL;
Bill Richardson72e344d2012-03-19 12:47:18 -0700700 char* keyblock_file = NULL;
701 char* signpubkey_file = NULL;
702 char* signprivkey_file = NULL;
703 char* version_str = NULL;
vbendeb00b90882010-10-21 13:46:16 -0700704 int version = -1;
Bill Richardson72e344d2012-03-19 12:47:18 -0700705 char* vmlinuz_file = NULL;
706 char* bootloader_file = NULL;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700707 char* config_file = NULL;
Bill Richardson72e344d2012-03-19 12:47:18 -0700708 arch_t arch = ARCH_X86;
709 char *address_str = NULL;
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +0800710 uint64_t kernel_body_load_address = CROS_32BIT_ENTRY_ADDR;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700711 int mode = 0;
712 int parse_error = 0;
Randall Spanglerae87b922011-05-12 13:27:28 -0700713 uint64_t min_version = 0;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700714 char* e;
Bill Richardson72e344d2012-03-19 12:47:18 -0700715 int i;
716 VbPrivateKey* signpriv_key = NULL;
717 VbPublicKey* signpub_key = NULL;
718 uint8_t* kernel_blob = NULL;
719 uint64_t kernel_size = 0;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700720
721 char *progname = strrchr(argv[0], '/');
722 if (progname)
723 progname++;
724 else
725 progname = argv[0];
726
vbendebb2b0fcc2010-07-15 15:09:47 -0700727 while (((i = getopt_long(argc, argv, ":", long_opts, NULL)) != -1) &&
728 !parse_error) {
Randall Spangler7d6898d2010-06-11 09:22:13 -0700729 switch (i) {
Bill Richardson72e344d2012-03-19 12:47:18 -0700730 default:
731 case '?':
732 /* Unhandled option */
733 parse_error = 1;
734 break;
735
736 case 0:
737 /* silently handled option */
738 break;
739
740 case OPT_MODE_PACK:
741 case OPT_MODE_REPACK:
742 case OPT_MODE_VERIFY:
743 if (mode && (mode != i)) {
744 fprintf(stderr, "Only a single mode can be specified\n");
Randall Spangler7d6898d2010-06-11 09:22:13 -0700745 parse_error = 1;
746 break;
Bill Richardson72e344d2012-03-19 12:47:18 -0700747 }
748 mode = i;
749 filename = optarg;
750 break;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700751
Bill Richardson72e344d2012-03-19 12:47:18 -0700752 case OPT_ARCH:
753 /* check the first 3 characters to also detect x86_64 */
754 if ((!strncasecmp(optarg, "x86", 3)) ||
755 (!strcasecmp(optarg, "amd64")))
756 arch = ARCH_X86;
757 else if (!strcasecmp(optarg, "arm"))
758 arch = ARCH_ARM;
Gaurav Shah36ba3402014-05-14 17:28:27 -0700759 else if (!strcasecmp(optarg, "mips"))
760 arch = ARCH_MIPS;
Bill Richardson72e344d2012-03-19 12:47:18 -0700761 else {
762 fprintf(stderr, "Unknown architecture string: %s\n", optarg);
763 parse_error = 1;
764 }
765 break;
Bill Richardson4f36ef32010-08-09 17:50:14 -0700766
Bill Richardson72e344d2012-03-19 12:47:18 -0700767 case OPT_OLDBLOB:
768 oldfile = optarg;
769 break;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700770
Bill Richardson72e344d2012-03-19 12:47:18 -0700771 case OPT_KLOADADDR:
772 address_str = optarg;
773 kernel_body_load_address = strtoul(optarg, &e, 0);
774 if (!*optarg || (e && *e)) {
775 fprintf(stderr, "Invalid --kloadaddr\n");
776 parse_error = 1;
777 }
778 break;
Che-Liang Chiou03762032011-02-22 11:16:51 +0800779
Bill Richardson72e344d2012-03-19 12:47:18 -0700780 case OPT_KEYBLOCK:
781 keyblock_file = optarg;
782 break;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700783
Bill Richardson72e344d2012-03-19 12:47:18 -0700784 case OPT_SIGNPUBKEY:
785 signpubkey_file = optarg;
786 break;
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +0800787
Bill Richardson72e344d2012-03-19 12:47:18 -0700788 case OPT_SIGNPRIVATE:
789 signprivkey_file = optarg;
790 break;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700791
Bill Richardson72e344d2012-03-19 12:47:18 -0700792 case OPT_VMLINUZ:
793 vmlinuz_file = optarg;
794 break;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700795
Bill Richardson72e344d2012-03-19 12:47:18 -0700796 case OPT_BOOTLOADER:
797 bootloader_file = optarg;
798 break;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700799
Bill Richardson72e344d2012-03-19 12:47:18 -0700800 case OPT_CONFIG:
801 config_file = optarg;
802 break;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700803
Bill Richardson72e344d2012-03-19 12:47:18 -0700804 case OPT_VBLOCKONLY:
805 opt_vblockonly = 1;
806 break;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700807
Bill Richardson72e344d2012-03-19 12:47:18 -0700808 case OPT_VERSION:
809 version_str = optarg;
810 version = strtoul(optarg, &e, 0);
811 if (!*optarg || (e && *e)) {
812 fprintf(stderr, "Invalid --version\n");
813 parse_error = 1;
814 }
815 break;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700816
Bill Richardson72e344d2012-03-19 12:47:18 -0700817 case OPT_MINVERSION:
818 min_version = strtoul(optarg, &e, 0);
819 if (!*optarg || (e && *e)) {
820 fprintf(stderr, "Invalid --minversion\n");
821 parse_error = 1;
822 }
823 break;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700824
Bill Richardson72e344d2012-03-19 12:47:18 -0700825 case OPT_PAD:
826 opt_pad = strtoul(optarg, &e, 0);
827 if (!*optarg || (e && *e)) {
828 fprintf(stderr, "Invalid --pad\n");
829 parse_error = 1;
830 }
831 break;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700832 }
833 }
834
835 if (parse_error)
Bill Richardsona08b5c92010-06-30 21:59:43 -0700836 return PrintHelp(progname);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700837
838 switch(mode) {
Bill Richardson72e344d2012-03-19 12:47:18 -0700839 case OPT_MODE_PACK:
Bill Richardsona08b5c92010-06-30 21:59:43 -0700840
Bill Richardson72e344d2012-03-19 12:47:18 -0700841 /* Required */
vbendebb2b0fcc2010-07-15 15:09:47 -0700842
Bill Richardson72e344d2012-03-19 12:47:18 -0700843 if (!keyblock_file)
844 Fatal("Missing required keyblock file.\n");
Bill Richardsona08b5c92010-06-30 21:59:43 -0700845
Bill Richardson72e344d2012-03-19 12:47:18 -0700846 g_keyblock = (VbKeyBlockHeader*)ReadFile(keyblock_file, 0);
847 if (!g_keyblock)
848 Fatal("Error reading key block.\n");
Bill Richardsona08b5c92010-06-30 21:59:43 -0700849
Bill Richardson72e344d2012-03-19 12:47:18 -0700850 if (!signprivkey_file)
851 Fatal("Missing required signprivate file.\n");
852
853 signpriv_key = PrivateKeyRead(signprivkey_file);
854 if (!signpriv_key)
855 Fatal("Error reading signing key.\n");
856
857 /* Optional */
858
859 if (config_file) {
860 Debug("Reading %s\n", config_file);
861 g_config_data = ReadConfigFile(config_file, &g_config_size);
Lucian Cojocar2312ab62012-07-30 15:21:49 -0700862 if (!g_config_data)
863 Fatal("Error reading config file.\n");
Bill Richardson72e344d2012-03-19 12:47:18 -0700864 }
865
866 if (vmlinuz_file)
867 if (!ImportVmlinuzFile(vmlinuz_file, arch, kernel_body_load_address))
868 Fatal("Error reading kernel file.\n");
869
870 if (bootloader_file) {
871 Debug("Reading %s\n", bootloader_file);
872 g_bootloader_data = ReadFile(bootloader_file, &g_bootloader_size);
873 if (!g_bootloader_data)
874 Fatal("Error reading bootloader file.\n");
875 Debug(" bootloader file size=0x%" PRIx64 "\n", g_bootloader_size);
876 }
877
878 /* Do it */
879
880 kernel_blob = CreateKernelBlob(kernel_body_load_address, arch,
881 &kernel_size);
882
883 return Pack(filename, kernel_blob, kernel_size,
884 version, kernel_body_load_address,
885 signpriv_key);
886
887 case OPT_MODE_REPACK:
888
889 /* Required */
890
891 if (!signprivkey_file)
892 Fatal("Missing required signprivate file.\n");
893
894 signpriv_key = PrivateKeyRead(signprivkey_file);
895 if (!signpriv_key)
896 Fatal("Error reading signing key.\n");
897
898 if (!oldfile)
899 Fatal("Missing previously packed blob.\n");
900
901 /* Load the old blob */
902
903 kernel_blob = ReadOldBlobFromFileOrDie(oldfile, &kernel_size);
904 if (0 != Verify(kernel_blob, kernel_size, 0, 0, 0))
905 Fatal("The oldblob doesn't verify\n");
906
907 /* Take it apart */
908
909 UnpackKernelBlob(kernel_blob, kernel_size);
910 free(kernel_blob);
911
912 /* Load optional params */
913
914 if (!version_str)
915 version = g_preamble->kernel_version;
916
917 if (!address_str)
918 kernel_body_load_address = g_preamble->body_load_address;
919
920 if (config_file) {
921 if (g_config_data)
922 free(g_config_data);
923 Debug("Reading %s\n", config_file);
924 g_config_data = ReadConfigFile(config_file, &g_config_size);
Lucian Cojocar2312ab62012-07-30 15:21:49 -0700925 if (!g_config_data)
926 Fatal("Error reading config file.\n");
Bill Richardson72e344d2012-03-19 12:47:18 -0700927 }
928
929 if (keyblock_file) {
930 if (g_keyblock)
931 free(g_keyblock);
932 g_keyblock = (VbKeyBlockHeader*)ReadFile(keyblock_file, 0);
933 if (!g_keyblock)
934 Fatal("Error reading key block.\n");
935 }
936
937 /* Put it back together */
938
939 kernel_blob = CreateKernelBlob(kernel_body_load_address, arch,
940 &kernel_size);
941
942 return Pack(filename, kernel_blob, kernel_size,
943 version, kernel_body_load_address,
944 signpriv_key);
945
946
947 case OPT_MODE_VERIFY:
948
949 /* Optional */
950
951 if (signpubkey_file) {
952 signpub_key = PublicKeyRead(signpubkey_file);
953 if (!signpub_key)
954 Fatal("Error reading public key.\n");
955 }
956
957 /* Do it */
958
959 kernel_blob = ReadOldBlobFromFileOrDie(filename, &kernel_size);
960
961 return Verify(kernel_blob, kernel_size, signpub_key,
962 keyblock_file, min_version);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700963 }
Bill Richardson72e344d2012-03-19 12:47:18 -0700964
965 fprintf(stderr, "You must specify a mode: --pack, --repack or --verify\n");
966 return PrintHelp(progname);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700967}