blob: 688d57a11d3899fab6759f111e2b25af71eaf435 [file] [log] [blame]
Randall Spanglerae87b922011-05-12 13:27:28 -07001/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
Randall Spangler7d6898d2010-06-11 09:22:13 -07002 * Use of this source code is governed by a BSD-style license that can be
3 * found in the LICENSE file.
4 *
5 * Verified boot kernel utility
6 */
7
Bill Richardsona08b5c92010-06-30 21:59:43 -07008#include <errno.h>
Randall Spangler7d6898d2010-06-11 09:22:13 -07009#include <getopt.h>
10#include <inttypes.h> /* For PRIu64 */
Bill Richardson249677d2010-06-23 11:16:37 -070011#include <stdarg.h>
Randall Spangler7d6898d2010-06-11 09:22:13 -070012#include <stddef.h>
13#include <stdio.h>
14#include <stdlib.h>
Bill Richardsona08b5c92010-06-30 21:59:43 -070015#include <string.h>
16#include <sys/stat.h>
17#include <sys/types.h>
Randall Spangler7d6898d2010-06-11 09:22:13 -070018#include <unistd.h>
19
20#include "cryptolib.h"
21#include "host_common.h"
22#include "kernel_blob.h"
23#include "vboot_common.h"
24
25
Bill Richardson249677d2010-06-23 11:16:37 -070026/* Global opt */
27static int opt_debug = 0;
28
Bill Richardsona08b5c92010-06-30 21:59:43 -070029static const int DEFAULT_PADDING = 65536;
Bill Richardson249677d2010-06-23 11:16:37 -070030
Randall Spangler7d6898d2010-06-11 09:22:13 -070031/* Command line options */
32enum {
33 OPT_MODE_PACK = 1000,
Bill Richardsona08b5c92010-06-30 21:59:43 -070034 OPT_MODE_REPACK,
Randall Spangler7d6898d2010-06-11 09:22:13 -070035 OPT_MODE_VERIFY,
Che-Liang Chiou03762032011-02-22 11:16:51 +080036 OPT_ARCH,
Bill Richardsona08b5c92010-06-30 21:59:43 -070037 OPT_OLDBLOB,
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +080038 OPT_KLOADADDR,
Randall Spangler7d6898d2010-06-11 09:22:13 -070039 OPT_KEYBLOCK,
40 OPT_SIGNPUBKEY,
41 OPT_SIGNPRIVATE,
42 OPT_VERSION,
43 OPT_VMLINUZ,
44 OPT_BOOTLOADER,
45 OPT_CONFIG,
Bill Richardsona08b5c92010-06-30 21:59:43 -070046 OPT_VBLOCKONLY,
Randall Spangler7d6898d2010-06-11 09:22:13 -070047 OPT_PAD,
vbendebb2b0fcc2010-07-15 15:09:47 -070048 OPT_VERBOSE,
Randall Spanglerae87b922011-05-12 13:27:28 -070049 OPT_MINVERSION,
Randall Spangler7d6898d2010-06-11 09:22:13 -070050};
51
Che-Liang Chiou03762032011-02-22 11:16:51 +080052enum {
53 ARCH_ARM,
54 ARCH_X86 /* default */
55};
56
Randall Spangler7d6898d2010-06-11 09:22:13 -070057static struct option long_opts[] = {
58 {"pack", 1, 0, OPT_MODE_PACK },
Bill Richardsona08b5c92010-06-30 21:59:43 -070059 {"repack", 1, 0, OPT_MODE_REPACK },
Randall Spangler7d6898d2010-06-11 09:22:13 -070060 {"verify", 1, 0, OPT_MODE_VERIFY },
Che-Liang Chiou03762032011-02-22 11:16:51 +080061 {"arch", 1, 0, OPT_ARCH },
Bill Richardsona08b5c92010-06-30 21:59:43 -070062 {"oldblob", 1, 0, OPT_OLDBLOB },
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +080063 {"kloadaddr", 1, 0, OPT_KLOADADDR },
Randall Spangler7d6898d2010-06-11 09:22:13 -070064 {"keyblock", 1, 0, OPT_KEYBLOCK },
65 {"signpubkey", 1, 0, OPT_SIGNPUBKEY },
66 {"signprivate", 1, 0, OPT_SIGNPRIVATE },
67 {"version", 1, 0, OPT_VERSION },
Randall Spanglerae87b922011-05-12 13:27:28 -070068 {"minversion", 1, 0, OPT_MINVERSION },
Randall Spangler7d6898d2010-06-11 09:22:13 -070069 {"vmlinuz", 1, 0, OPT_VMLINUZ },
70 {"bootloader", 1, 0, OPT_BOOTLOADER },
71 {"config", 1, 0, OPT_CONFIG },
Bill Richardsona08b5c92010-06-30 21:59:43 -070072 {"vblockonly", 0, 0, OPT_VBLOCKONLY },
Randall Spangler7d6898d2010-06-11 09:22:13 -070073 {"pad", 1, 0, OPT_PAD },
vbendebb2b0fcc2010-07-15 15:09:47 -070074 {"verbose", 0, 0, OPT_VERBOSE },
Bill Richardson249677d2010-06-23 11:16:37 -070075 {"debug", 0, &opt_debug, 1 },
Randall Spangler7d6898d2010-06-11 09:22:13 -070076 {NULL, 0, 0, 0}
77};
78
79
80/* Print help and return error */
Bill Richardsona08b5c92010-06-30 21:59:43 -070081static int PrintHelp(char *progname) {
82 fprintf(stderr,
83 "This program creates, signs, and verifies the kernel blob\n");
84 fprintf(stderr,
85 "\n"
86 "Usage: %s --pack <file> [PARAMETERS]\n"
87 "\n"
88 " Required parameters:\n"
89 " --keyblock <file> Key block in .keyblock format\n"
Bill Richardson4f36ef32010-08-09 17:50:14 -070090 " --signprivate <file>"
91 " Private key to sign kernel data, in .vbprivk format\n"
Bill Richardsona08b5c92010-06-30 21:59:43 -070092 " --version <number> Kernel version\n"
93 " --vmlinuz <file> Linux kernel bzImage file\n"
94 " --bootloader <file> Bootloader stub\n"
vbendebb2b0fcc2010-07-15 15:09:47 -070095 " --config <file> Command line file\n"
Che-Liang Chiou03762032011-02-22 11:16:51 +080096 " --arch <arch> Cpu architecture (default x86)\n"
Bill Richardsona08b5c92010-06-30 21:59:43 -070097 "\n"
98 " Optional:\n"
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +080099 " --kloadaddr <address> Assign kernel body load address\n"
Bill Richardsona08b5c92010-06-30 21:59:43 -0700100 " --pad <number> Verification padding size in bytes\n"
101 " --vblockonly Emit just the verification blob\n",
102 progname);
103 fprintf(stderr,
104 "\nOR\n\n"
105 "Usage: %s --repack <file> [PARAMETERS]\n"
106 "\n"
vbendeb858fffb2010-10-06 09:51:44 -0700107 " Required parameters (of --keyblock, --config, and --version \n"
108 " at least one is required):\n"
Bill Richardsona08b5c92010-06-30 21:59:43 -0700109 " --keyblock <file> Key block in .keyblock format\n"
Bill Richardson4f36ef32010-08-09 17:50:14 -0700110 " --signprivate <file>"
111 " Private key to sign kernel data, in .vbprivk format\n"
Bill Richardsona08b5c92010-06-30 21:59:43 -0700112 " --oldblob <file> Previously packed kernel blob\n"
vbendebb2b0fcc2010-07-15 15:09:47 -0700113 " --config <file> New command line file\n"
vbendeb858fffb2010-10-06 09:51:44 -0700114 " --version <number> Kernel version\n"
Bill Richardsona08b5c92010-06-30 21:59:43 -0700115 "\n"
116 " Optional:\n"
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +0800117 " --kloadaddr <address> Assign kernel body load address\n"
Bill Richardsona08b5c92010-06-30 21:59:43 -0700118 " --pad <number> Verification padding size in bytes\n"
119 " --vblockonly Emit just the verification blob\n",
120 progname);
121 fprintf(stderr,
122 "\nOR\n\n"
123 "Usage: %s --verify <file> [PARAMETERS]\n"
124 "\n"
vbendebb2b0fcc2010-07-15 15:09:47 -0700125 " Optional:\n"
Bill Richardson4f36ef32010-08-09 17:50:14 -0700126 " --signpubkey <file>"
127 " Public key to verify kernel keyblock, in .vbpubk format\n"
vbendebb2b0fcc2010-07-15 15:09:47 -0700128 " --verbose Print a more detailed report\n"
Will Drewry9342f882010-10-26 10:22:05 -0500129 " --keyblock <file>"
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +0800130 " Outputs the verified key block, in .keyblock format\n"
131 " --kloadaddr <address> Assign kernel body load address\n"
Randall Spangler7ecb39d2011-05-12 15:37:45 -0700132 " --pad <number> Verification padding size in bytes\n"
Randall Spanglerae87b922011-05-12 13:27:28 -0700133 " --minversion <number> Minimum combined kernel key version\n"
134 " and kernel version\n"
Bill Richardsona08b5c92010-06-30 21:59:43 -0700135 "\n",
136 progname);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700137 return 1;
138}
139
Bill Richardson249677d2010-06-23 11:16:37 -0700140static void Debug(const char *format, ...) {
141 if (!opt_debug)
142 return;
143
144 va_list ap;
145 va_start(ap, format);
146 fprintf(stderr, "DEBUG: ");
147 vfprintf(stderr, format, ap);
148 va_end(ap);
149}
150
Randall Spangler32a65262011-06-27 10:49:11 -0700151
Bill Richardson2f6a71f2010-10-14 09:25:39 -0700152/* Return an explanation when fread() fails. */
153static const char *error_fread(FILE *fp) {
154 const char *retval = "beats me why";
155 if (feof(fp))
156 retval = "EOF";
157 else if (ferror(fp))
158 retval = strerror(errno);
159 clearerr(fp);
160 return retval;
161}
Randall Spangler7d6898d2010-06-11 09:22:13 -0700162
163/* Return the smallest integral multiple of [alignment] that is equal
164 * to or greater than [val]. Used to determine the number of
165 * pages/sectors/blocks/whatever needed to contain [val]
166 * items/bytes/etc. */
167static uint64_t roundup(uint64_t val, uint64_t alignment) {
168 uint64_t rem = val % alignment;
169 if ( rem )
170 return val + (alignment - rem);
171 return val;
172}
173
174
175/* Match regexp /\b--\b/ to delimit the start of the kernel commandline. If we
176 * don't find one, we'll use the whole thing. */
177static unsigned int find_cmdline_start(char *input, unsigned int max_len) {
178 int start = 0;
179 int i;
180 for(i = 0; i < max_len - 1 && input[i]; i++) {
181 if ('-' == input[i] && '-' == input[i + 1]) { /* found a "--" */
182 if ((i == 0 || ' ' == input[i - 1]) && /* nothing before it */
183 (i + 2 >= max_len || ' ' == input[i+2])) { /* nothing after it */
184 start = i+2; /* note: hope there's a trailing '\0' */
185 break;
186 }
187 }
188 }
189 while(' ' == input[start]) /* skip leading spaces */
190 start++;
191
192 return start;
193}
194
195
Bill Richardsonc8b9ca62012-03-14 10:54:05 -0700196
197
Bill Richardsona08b5c92010-06-30 21:59:43 -0700198typedef struct blob_s {
199 /* Stuff needed by VbKernelPreambleHeader */
200 uint64_t kernel_version;
Bill Richardsonc8b9ca62012-03-14 10:54:05 -0700201 uint64_t bootloader_address; /* in RAM, after loading from disk */
Bill Richardsona08b5c92010-06-30 21:59:43 -0700202 uint64_t bootloader_size;
203 /* Raw kernel blob data */
Bill Richardsonc8b9ca62012-03-14 10:54:05 -0700204 uint64_t kern_blob_size;
205 uint8_t *kern_blob;
vbendebb2b0fcc2010-07-15 15:09:47 -0700206
Bill Richardsonc8b9ca62012-03-14 10:54:05 -0700207 /* These fields are not always initialized. When they are, they point to the
208 * verification block as it's found on-disk. See
209 * http://www.chromium.org/chromium-os/chromiumos-design-docs/disk-format */
210 uint8_t *vblock_buf; /* typically includes padding */
211 VbKeyBlockHeader* key_block; /* within vblock_buf, don't free it */
212 VbKernelPreambleHeader* preamble; /* ditto */
Bill Richardsona08b5c92010-06-30 21:59:43 -0700213} blob_t;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700214
vbendebb2b0fcc2010-07-15 15:09:47 -0700215/* Given a blob return the location of the kernel command line buffer. */
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +0800216static char* BpCmdLineLocation(blob_t *bp, uint64_t kernel_body_load_address)
vbendebb2b0fcc2010-07-15 15:09:47 -0700217{
Bill Richardsonc8b9ca62012-03-14 10:54:05 -0700218 return (char*)(bp->kern_blob +
219 bp->bootloader_address - kernel_body_load_address -
vbendebb2b0fcc2010-07-15 15:09:47 -0700220 CROS_CONFIG_SIZE - CROS_PARAMS_SIZE);
221}
Bill Richardsona08b5c92010-06-30 21:59:43 -0700222
223static void FreeBlob(blob_t *bp) {
224 if (bp) {
Bill Richardsonc8b9ca62012-03-14 10:54:05 -0700225 if (bp->kern_blob)
226 free(bp->kern_blob);
227 if (bp->vblock_buf)
228 free(bp->vblock_buf);
Randall Spangler32a65262011-06-27 10:49:11 -0700229 free(bp);
Bill Richardsona08b5c92010-06-30 21:59:43 -0700230 }
231}
232
vbendebb2b0fcc2010-07-15 15:09:47 -0700233/*
234 * Read the kernel command line from a file. Get rid of \n characters along
235 * the way and verify that the line fits into a 4K buffer.
236 *
237 * Return the buffer contaning the line on success (and set the line length
238 * using the passed in parameter), or NULL in case something goes wrong.
239 */
240static uint8_t* ReadConfigFile(const char* config_file, uint64_t* config_size)
241{
242 uint8_t* config_buf;
243 int ii;
244
245 config_buf = ReadFile(config_file, config_size);
246 Debug(" config file size=0x%" PRIx64 "\n", *config_size);
247 if (CROS_CONFIG_SIZE <= *config_size) { /* need room for trailing '\0' */
Randall Spangler32a65262011-06-27 10:49:11 -0700248 VbExError("Config file %s is too large (>= %d bytes)\n",
249 config_file, CROS_CONFIG_SIZE);
vbendebb2b0fcc2010-07-15 15:09:47 -0700250 return NULL;
251 }
252
253 /* Replace newlines with spaces */
254 for (ii = 0; ii < *config_size; ii++) {
255 if ('\n' == config_buf[ii]) {
256 config_buf[ii] = ' ';
257 }
258 }
259 return config_buf;
260}
261
Bill Richardsona08b5c92010-06-30 21:59:43 -0700262/* Create a blob from its components */
263static blob_t *NewBlob(uint64_t version,
264 const char* vmlinuz,
265 const char* bootloader_file,
Che-Liang Chiou03762032011-02-22 11:16:51 +0800266 const char* config_file,
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +0800267 int arch,
268 uint64_t kernel_body_load_address) {
Che-Liang Chiou03762032011-02-22 11:16:51 +0800269 blob_t* bp;
270 struct linux_kernel_header* lh = 0;
271 struct linux_kernel_params* params = 0;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700272 uint8_t* config_buf;
273 uint64_t config_size;
274 uint8_t* bootloader_buf;
275 uint64_t bootloader_size;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700276 uint8_t* kernel_buf;
277 uint64_t kernel_size;
278 uint64_t kernel32_start = 0;
279 uint64_t kernel32_size = 0;
280 uint32_t cmdline_addr;
Bill Richardsonc8b9ca62012-03-14 10:54:05 -0700281 uint8_t* kern_blob = NULL;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700282 uint64_t now = 0;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700283
Randall Spangler7d6898d2010-06-11 09:22:13 -0700284 if (!vmlinuz || !bootloader_file || !config_file) {
Randall Spangler32a65262011-06-27 10:49:11 -0700285 VbExError("Must specify all input files\n");
Bill Richardsona08b5c92010-06-30 21:59:43 -0700286 return 0;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700287 }
288
Randall Spangler32a65262011-06-27 10:49:11 -0700289 bp = (blob_t *)malloc(sizeof(blob_t));
Bill Richardsona08b5c92010-06-30 21:59:43 -0700290 if (!bp) {
Randall Spangler32a65262011-06-27 10:49:11 -0700291 VbExError("Couldn't allocate bytes for blob_t.\n");
Bill Richardsona08b5c92010-06-30 21:59:43 -0700292 return 0;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700293 }
vbendebb2b0fcc2010-07-15 15:09:47 -0700294
295 Memset(bp, 0, sizeof(*bp));
Bill Richardsona08b5c92010-06-30 21:59:43 -0700296 bp->kernel_version = version;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700297
298 /* Read the config file */
Bill Richardson249677d2010-06-23 11:16:37 -0700299 Debug("Reading %s\n", config_file);
vbendebb2b0fcc2010-07-15 15:09:47 -0700300 config_buf = ReadConfigFile(config_file, &config_size);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700301 if (!config_buf)
Bill Richardsona08b5c92010-06-30 21:59:43 -0700302 return 0;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700303
304 /* Read the bootloader */
Bill Richardson249677d2010-06-23 11:16:37 -0700305 Debug("Reading %s\n", bootloader_file);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700306 bootloader_buf = ReadFile(bootloader_file, &bootloader_size);
307 if (!bootloader_buf)
Bill Richardsona08b5c92010-06-30 21:59:43 -0700308 return 0;
Bill Richardson249677d2010-06-23 11:16:37 -0700309 Debug(" bootloader file size=0x%" PRIx64 "\n", bootloader_size);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700310
311 /* Read the kernel */
Bill Richardson249677d2010-06-23 11:16:37 -0700312 Debug("Reading %s\n", vmlinuz);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700313 kernel_buf = ReadFile(vmlinuz, &kernel_size);
314 if (!kernel_buf)
Bill Richardsona08b5c92010-06-30 21:59:43 -0700315 return 0;
Bill Richardson249677d2010-06-23 11:16:37 -0700316 Debug(" kernel file size=0x%" PRIx64 "\n", kernel_size);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700317 if (!kernel_size) {
Randall Spangler32a65262011-06-27 10:49:11 -0700318 VbExError("Empty kernel file\n");
Bill Richardsona08b5c92010-06-30 21:59:43 -0700319 return 0;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700320 }
321
Che-Liang Chiou03762032011-02-22 11:16:51 +0800322 if (arch == ARCH_X86) {
323 /* The first part of vmlinuz is a header, followed by a real-mode
324 * boot stub. We only want the 32-bit part. */
325 lh = (struct linux_kernel_header *)kernel_buf;
326 kernel32_start = (lh->setup_sects + 1) << 9;
327 if (kernel32_start >= kernel_size) {
Randall Spangler32a65262011-06-27 10:49:11 -0700328 VbExError("Malformed kernel\n");
Che-Liang Chiou03762032011-02-22 11:16:51 +0800329 return 0;
330 }
331 } else
332 kernel32_start = 0;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700333 kernel32_size = kernel_size - kernel32_start;
Bill Richardson249677d2010-06-23 11:16:37 -0700334 Debug(" kernel32_start=0x%" PRIx64 "\n", kernel32_start);
335 Debug(" kernel32_size=0x%" PRIx64 "\n", kernel32_size);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700336
Bill Richardsonc8b9ca62012-03-14 10:54:05 -0700337 /* Allocate and zero the space we need for the kernel blob. */
338 bp->kern_blob_size = roundup(kernel32_size, CROS_ALIGN) +
Randall Spangler7d6898d2010-06-11 09:22:13 -0700339 CROS_CONFIG_SIZE +
340 CROS_PARAMS_SIZE +
341 roundup(bootloader_size, CROS_ALIGN);
Bill Richardsonc8b9ca62012-03-14 10:54:05 -0700342 Debug("kern_blob_size=0x%" PRIx64 "\n", bp->kern_blob_size);
343 kern_blob = (uint8_t *)malloc(bp->kern_blob_size);
344 if (!kern_blob) {
345 VbExError("Couldn't allocate %ld bytes.\n", bp->kern_blob_size);
Bill Richardsona08b5c92010-06-30 21:59:43 -0700346 return 0;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700347 }
Bill Richardsonc8b9ca62012-03-14 10:54:05 -0700348 Memset(kern_blob, 0, bp->kern_blob_size);
349 bp->kern_blob = kern_blob;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700350
351 /* Copy the 32-bit kernel. */
Bill Richardsonc8b9ca62012-03-14 10:54:05 -0700352 Debug("kernel goes at kern_blob+0x%" PRIx64 "\n", now);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700353 if (kernel32_size)
Bill Richardsonc8b9ca62012-03-14 10:54:05 -0700354 Memcpy(kern_blob + now, kernel_buf + kernel32_start, kernel32_size);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700355 now += roundup(now + kernel32_size, CROS_ALIGN);
356
Bill Richardsonc8b9ca62012-03-14 10:54:05 -0700357 Debug("config goes at kern_blob+0x%" PRIx64 "\n", now);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700358 /* Find the load address of the commandline. We'll need it later. */
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +0800359 cmdline_addr = kernel_body_load_address + now +
Randall Spangler7d6898d2010-06-11 09:22:13 -0700360 find_cmdline_start((char *)config_buf, config_size);
Bill Richardson249677d2010-06-23 11:16:37 -0700361 Debug(" cmdline_addr=0x%" PRIx64 "\n", cmdline_addr);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700362
363 /* Copy the config. */
364 if (config_size)
Bill Richardsonc8b9ca62012-03-14 10:54:05 -0700365 Memcpy(kern_blob + now, config_buf, config_size);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700366 now += CROS_CONFIG_SIZE;
367
368 /* The zeropage data is next. Overlay the linux_kernel_header onto it, and
369 * tweak a few fields. */
Bill Richardsonc8b9ca62012-03-14 10:54:05 -0700370 Debug("params goes at kern_blob+0x%" PRIx64 "\n", now);
371 params = (struct linux_kernel_params *)(kern_blob + now);
Che-Liang Chiou03762032011-02-22 11:16:51 +0800372 if (arch == ARCH_X86)
373 Memcpy(&(params->setup_sects), &(lh->setup_sects),
374 sizeof(*lh) - offsetof(struct linux_kernel_header, setup_sects));
375 else
376 Memset(&(params->setup_sects), 0,
377 sizeof(*lh) - offsetof(struct linux_kernel_header, setup_sects));
Randall Spangler7d6898d2010-06-11 09:22:13 -0700378 params->boot_flag = 0;
379 params->ramdisk_image = 0; /* we don't support initrd */
380 params->ramdisk_size = 0;
381 params->type_of_loader = 0xff;
382 params->cmd_line_ptr = cmdline_addr;
Che-Liang Chiou475bf442010-08-23 11:20:44 +0800383 /* A fake e820 memory map with 2 entries */
384 params->n_e820_entry = 2;
385 params->e820_entries[0].start_addr = 0x00000000;
386 params->e820_entries[0].segment_size = 0x00001000;
387 params->e820_entries[0].segment_type = E820_TYPE_RAM;
388 params->e820_entries[1].start_addr = 0xfffff000;
389 params->e820_entries[1].segment_size = 0x00001000;
390 params->e820_entries[1].segment_type = E820_TYPE_RESERVED;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700391 now += CROS_PARAMS_SIZE;
392
393 /* Finally, append the bootloader. Remember where it will load in
394 * memory, too. */
Bill Richardsonc8b9ca62012-03-14 10:54:05 -0700395 Debug("bootloader goes at kern_blob+0x%" PRIx64 "\n", now);
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +0800396 bp->bootloader_address = kernel_body_load_address + now;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700397 bp->bootloader_size = roundup(bootloader_size, CROS_ALIGN);
398 Debug(" bootloader_address=0x%" PRIx64 "\n", bp->bootloader_address);
399 Debug(" bootloader_size=0x%" PRIx64 "\n", bp->bootloader_size);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700400 if (bootloader_size)
Bill Richardsonc8b9ca62012-03-14 10:54:05 -0700401 Memcpy(kern_blob + now, bootloader_buf, bootloader_size);
Bill Richardsona08b5c92010-06-30 21:59:43 -0700402 now += bp->bootloader_size;
Bill Richardsonc8b9ca62012-03-14 10:54:05 -0700403 Debug("end of kern_blob at kern_blob+0x%" PRIx64 "\n", now);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700404
405 /* Free input buffers */
Randall Spangler32a65262011-06-27 10:49:11 -0700406 free(kernel_buf);
407 free(config_buf);
408 free(bootloader_buf);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700409
Bill Richardsona08b5c92010-06-30 21:59:43 -0700410 /* Success */
411 return bp;
412}
413
414
415/* Pull the blob_t stuff out of a prepacked kernel blob file */
Randall Spangler7ecb39d2011-05-12 15:37:45 -0700416static blob_t *OldBlob(const char* filename, uint64_t pad) {
vbendebb2b0fcc2010-07-15 15:09:47 -0700417 FILE* fp = NULL;
418 blob_t *bp = NULL;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700419 struct stat statbuf;
420 VbKeyBlockHeader* key_block;
421 VbKernelPreambleHeader* preamble;
422 uint64_t now = 0;
vbendebb2b0fcc2010-07-15 15:09:47 -0700423 uint8_t* buf = NULL;
424 int ret_error = 1;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700425
426 if (!filename) {
Randall Spangler32a65262011-06-27 10:49:11 -0700427 VbExError("Must specify prepacked blob to read\n");
Bill Richardsona08b5c92010-06-30 21:59:43 -0700428 return 0;
429 }
430
431 if (0 != stat(filename, &statbuf)) {
Randall Spangler32a65262011-06-27 10:49:11 -0700432 VbExError("Unable to stat %s: %s\n", filename, strerror(errno));
Bill Richardsona08b5c92010-06-30 21:59:43 -0700433 return 0;
434 }
435
436 Debug("%s size is 0x%" PRIx64 "\n", filename, statbuf.st_size);
Randall Spangler7ecb39d2011-05-12 15:37:45 -0700437 if (statbuf.st_size < pad) {
Randall Spangler32a65262011-06-27 10:49:11 -0700438 VbExError("%s is too small to be a valid kernel blob\n");
Bill Richardsona08b5c92010-06-30 21:59:43 -0700439 return 0;
440 }
441
442 Debug("Reading %s\n", filename);
443 fp = fopen(filename, "rb");
444 if (!fp) {
Randall Spangler32a65262011-06-27 10:49:11 -0700445 VbExError("Unable to open file %s: %s\n", filename, strerror(errno));
Bill Richardsona08b5c92010-06-30 21:59:43 -0700446 return 0;
447 }
448
Randall Spangler32a65262011-06-27 10:49:11 -0700449 buf = malloc(pad);
vbendebb2b0fcc2010-07-15 15:09:47 -0700450 if (!buf) {
Randall Spangler32a65262011-06-27 10:49:11 -0700451 VbExError("Unable to allocate padding\n");
vbendebb2b0fcc2010-07-15 15:09:47 -0700452 goto unwind_oldblob;
453 }
454
Randall Spangler7ecb39d2011-05-12 15:37:45 -0700455 if (1 != fread(buf, pad, 1, fp)) {
Randall Spangler32a65262011-06-27 10:49:11 -0700456 VbExError("Unable to read header from %s: %s\n", filename, error_fread(fp));
vbendebb2b0fcc2010-07-15 15:09:47 -0700457 goto unwind_oldblob;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700458 }
459
460 /* Skip the key block */
461 key_block = (VbKeyBlockHeader*)buf;
462 Debug("Keyblock is 0x%" PRIx64 " bytes\n", key_block->key_block_size);
463 now += key_block->key_block_size;
464 if (now > statbuf.st_size) {
Randall Spangler32a65262011-06-27 10:49:11 -0700465 VbExError("key_block_size advances past the end of the blob\n");
vbendebb2b0fcc2010-07-15 15:09:47 -0700466 goto unwind_oldblob;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700467 }
Randall Spangler7ecb39d2011-05-12 15:37:45 -0700468 if (now > pad) {
Randall Spangler32a65262011-06-27 10:49:11 -0700469 VbExError("key_block_size advances past %" PRIu64 " byte padding\n", pad);
Randall Spangler7ecb39d2011-05-12 15:37:45 -0700470 goto unwind_oldblob;
471 }
Bill Richardsona08b5c92010-06-30 21:59:43 -0700472
473 /* Skip the preamble */
474 preamble = (VbKernelPreambleHeader*)(buf + now);
475 Debug("Preamble is 0x%" PRIx64 " bytes\n", preamble->preamble_size);
476 now += preamble->preamble_size;
477 if (now > statbuf.st_size) {
Randall Spangler32a65262011-06-27 10:49:11 -0700478 VbExError("preamble_size advances past the end of the blob\n");
vbendebb2b0fcc2010-07-15 15:09:47 -0700479 goto unwind_oldblob;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700480 }
Randall Spangler7ecb39d2011-05-12 15:37:45 -0700481 if (now > pad) {
Randall Spangler32a65262011-06-27 10:49:11 -0700482 VbExError("preamble_size advances past %" PRIu64 " byte padding\n", pad);
Randall Spangler7ecb39d2011-05-12 15:37:45 -0700483 goto unwind_oldblob;
484 }
Bill Richardsona08b5c92010-06-30 21:59:43 -0700485
486 /* Go find the kernel blob */
487 Debug("kernel blob is at offset 0x%" PRIx64 "\n", now);
488 if (0 != fseek(fp, now, SEEK_SET)) {
Randall Spangler32a65262011-06-27 10:49:11 -0700489 VbExError("Unable to seek to 0x%" PRIx64 " in %s: %s\n", now, filename,
Bill Richardsona08b5c92010-06-30 21:59:43 -0700490 strerror(errno));
vbendebb2b0fcc2010-07-15 15:09:47 -0700491 goto unwind_oldblob;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700492 }
493
494 /* Remember what we've got */
Randall Spangler32a65262011-06-27 10:49:11 -0700495 bp = (blob_t *)malloc(sizeof(blob_t));
Bill Richardsona08b5c92010-06-30 21:59:43 -0700496 if (!bp) {
Randall Spangler32a65262011-06-27 10:49:11 -0700497 VbExError("Couldn't allocate bytes for blob_t.\n");
vbendebb2b0fcc2010-07-15 15:09:47 -0700498 goto unwind_oldblob;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700499 }
500
Bill Richardsonc8b9ca62012-03-14 10:54:05 -0700501 bp->vblock_buf = buf;
vbendebb2b0fcc2010-07-15 15:09:47 -0700502 bp->key_block = key_block;
503 bp->preamble = preamble;
504
Bill Richardsona08b5c92010-06-30 21:59:43 -0700505 bp->kernel_version = preamble->kernel_version;
506 bp->bootloader_address = preamble->bootloader_address;
507 bp->bootloader_size = preamble->bootloader_size;
Bill Richardsonc8b9ca62012-03-14 10:54:05 -0700508 bp->kern_blob_size = preamble->body_signature.data_size;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700509
510 Debug(" kernel_version = %d\n", bp->kernel_version);
511 Debug(" bootloader_address = 0x%" PRIx64 "\n", bp->bootloader_address);
512 Debug(" bootloader_size = 0x%" PRIx64 "\n", bp->bootloader_size);
Bill Richardsonc8b9ca62012-03-14 10:54:05 -0700513 Debug(" kern_blob_size = 0x%" PRIx64 "\n", bp->kern_blob_size);
Bill Richardsona08b5c92010-06-30 21:59:43 -0700514
Bill Richardsonc8b9ca62012-03-14 10:54:05 -0700515 if (!bp->kern_blob_size) {
Randall Spangler32a65262011-06-27 10:49:11 -0700516 VbExError("No kernel blob found\n");
Bill Richardson2f6a71f2010-10-14 09:25:39 -0700517 goto unwind_oldblob;
518 }
519
Bill Richardsonc8b9ca62012-03-14 10:54:05 -0700520 bp->kern_blob = (uint8_t *)malloc(bp->kern_blob_size);
521 if (!bp->kern_blob) {
Randall Spangler32a65262011-06-27 10:49:11 -0700522 VbExError("Couldn't allocate 0x%" PRIx64 " bytes for blob_t.\n",
Bill Richardsonc8b9ca62012-03-14 10:54:05 -0700523 bp->kern_blob_size);
vbendebb2b0fcc2010-07-15 15:09:47 -0700524 goto unwind_oldblob;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700525 }
526
527 /* read it in */
Bill Richardsonc8b9ca62012-03-14 10:54:05 -0700528 if (1 != fread(bp->kern_blob, bp->kern_blob_size, 1, fp)) {
Randall Spangler32a65262011-06-27 10:49:11 -0700529 VbExError("Unable to read kernel blob from %s: %s\n", filename,
530 error_fread(fp));
vbendebb2b0fcc2010-07-15 15:09:47 -0700531 goto unwind_oldblob;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700532 }
533
vbendebb2b0fcc2010-07-15 15:09:47 -0700534 ret_error = 0;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700535
vbendebb2b0fcc2010-07-15 15:09:47 -0700536 /* done */
537unwind_oldblob:
538 fclose(fp);
539 if (ret_error) {
540 if (bp) {
541 FreeBlob(bp);
542 bp = NULL;
543 } else if (buf) {
Randall Spangler32a65262011-06-27 10:49:11 -0700544 free(buf);
vbendebb2b0fcc2010-07-15 15:09:47 -0700545 }
546 }
Bill Richardsona08b5c92010-06-30 21:59:43 -0700547 return bp;
548}
549
550
551/* Pack a .kernel */
552static int Pack(const char* outfile, const char* keyblock_file,
553 const char* signprivate, blob_t *bp, uint64_t pad,
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +0800554 int vblockonly,
555 uint64_t kernel_body_load_address) {
Bill Richardsona08b5c92010-06-30 21:59:43 -0700556 VbPrivateKey* signing_key;
557 VbSignature* body_sig;
558 VbKernelPreambleHeader* preamble;
559 VbKeyBlockHeader* key_block;
560 uint64_t key_block_size;
561 FILE* f;
562 uint64_t i;
Bill Richardsonc8b9ca62012-03-14 10:54:05 -0700563 uint64_t written = 0;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700564
565 if (!outfile) {
Randall Spangler32a65262011-06-27 10:49:11 -0700566 VbExError("Must specify output filename\n");
Bill Richardsona08b5c92010-06-30 21:59:43 -0700567 return 1;
568 }
vbendebb2b0fcc2010-07-15 15:09:47 -0700569 if ((!keyblock_file && !bp->key_block) || !signprivate) {
Randall Spangler32a65262011-06-27 10:49:11 -0700570 VbExError("Must specify all keys\n");
Bill Richardsona08b5c92010-06-30 21:59:43 -0700571 return 1;
572 }
573 if (!bp) {
Randall Spangler32a65262011-06-27 10:49:11 -0700574 VbExError("Refusing to pack invalid kernel blob\n");
Bill Richardsona08b5c92010-06-30 21:59:43 -0700575 return 1;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700576 }
vbendebb2b0fcc2010-07-15 15:09:47 -0700577
578 /* Get the key block and read the private key. */
579 if (keyblock_file) {
580 key_block = (VbKeyBlockHeader*)ReadFile(keyblock_file, &key_block_size);
581 if (!key_block) {
Randall Spangler32a65262011-06-27 10:49:11 -0700582 VbExError("Error reading key block.\n");
vbendebb2b0fcc2010-07-15 15:09:47 -0700583 return 1;
584 }
585 } else {
586 key_block = bp->key_block;
587 key_block_size = key_block->key_block_size;
588 }
589
Bill Richardsona08b5c92010-06-30 21:59:43 -0700590 if (pad < key_block->key_block_size) {
Randall Spangler32a65262011-06-27 10:49:11 -0700591 VbExError("Pad too small\n");
Bill Richardsona08b5c92010-06-30 21:59:43 -0700592 return 1;
593 }
594
Bill Richardsonabf05502010-07-01 10:22:06 -0700595 signing_key = PrivateKeyRead(signprivate);
Bill Richardsona08b5c92010-06-30 21:59:43 -0700596 if (!signing_key) {
Randall Spangler32a65262011-06-27 10:49:11 -0700597 VbExError("Error reading signing key.\n");
Bill Richardsona08b5c92010-06-30 21:59:43 -0700598 return 1;
599 }
600
Randall Spangler7d6898d2010-06-11 09:22:13 -0700601 /* Sign the kernel data */
Bill Richardsonc8b9ca62012-03-14 10:54:05 -0700602 body_sig = CalculateSignature(bp->kern_blob, bp->kern_blob_size, signing_key);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700603 if (!body_sig) {
Randall Spangler32a65262011-06-27 10:49:11 -0700604 VbExError("Error calculating body signature\n");
Randall Spangler7d6898d2010-06-11 09:22:13 -0700605 return 1;
606 }
607
608 /* Create preamble */
Bill Richardsona08b5c92010-06-30 21:59:43 -0700609 preamble = CreateKernelPreamble(bp->kernel_version,
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +0800610 kernel_body_load_address,
Bill Richardsona08b5c92010-06-30 21:59:43 -0700611 bp->bootloader_address,
612 bp->bootloader_size,
Randall Spangler7d6898d2010-06-11 09:22:13 -0700613 body_sig,
614 pad - key_block_size,
615 signing_key);
616 if (!preamble) {
Randall Spangler32a65262011-06-27 10:49:11 -0700617 VbExError("Error creating preamble.\n");
Randall Spangler7d6898d2010-06-11 09:22:13 -0700618 return 1;
619 }
620
621 /* Write the output file */
Bill Richardson249677d2010-06-23 11:16:37 -0700622 Debug("writing %s...\n", outfile);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700623 f = fopen(outfile, "wb");
624 if (!f) {
Randall Spangler32a65262011-06-27 10:49:11 -0700625 VbExError("Can't open output file %s\n", outfile);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700626 return 1;
627 }
Bill Richardson249677d2010-06-23 11:16:37 -0700628 Debug("0x%" PRIx64 " bytes of key_block\n", key_block_size);
629 Debug("0x%" PRIx64 " bytes of preamble\n", preamble->preamble_size);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700630 i = ((1 != fwrite(key_block, key_block_size, 1, f)) ||
Bill Richardsona08b5c92010-06-30 21:59:43 -0700631 (1 != fwrite(preamble, preamble->preamble_size, 1, f)));
Randall Spangler7d6898d2010-06-11 09:22:13 -0700632 if (i) {
Randall Spangler32a65262011-06-27 10:49:11 -0700633 VbExError("Can't write output file %s\n", outfile);
Bill Richardsona08b5c92010-06-30 21:59:43 -0700634 fclose(f);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700635 unlink(outfile);
636 return 1;
637 }
Bill Richardsonc8b9ca62012-03-14 10:54:05 -0700638 written += key_block_size;
639 written += preamble->preamble_size;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700640
Bill Richardsona08b5c92010-06-30 21:59:43 -0700641 if (!vblockonly) {
Bill Richardsonc8b9ca62012-03-14 10:54:05 -0700642 Debug("0x%" PRIx64 " bytes of kern_blob\n", bp->kern_blob_size);
643 i = (1 != fwrite(bp->kern_blob, bp->kern_blob_size, 1, f));
Bill Richardsona08b5c92010-06-30 21:59:43 -0700644 if (i) {
Randall Spangler32a65262011-06-27 10:49:11 -0700645 VbExError("Can't write output file %s\n", outfile);
Bill Richardsona08b5c92010-06-30 21:59:43 -0700646 fclose(f);
647 unlink(outfile);
648 return 1;
649 }
Bill Richardsonc8b9ca62012-03-14 10:54:05 -0700650 written += bp->kern_blob_size;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700651 }
Bill Richardsonc8b9ca62012-03-14 10:54:05 -0700652 Debug("0x%" PRIx64 " bytes total\n", written);
Bill Richardsona08b5c92010-06-30 21:59:43 -0700653 fclose(f);
654
Randall Spangler7d6898d2010-06-11 09:22:13 -0700655 /* Success */
656 return 0;
657}
658
vbendebb2b0fcc2010-07-15 15:09:47 -0700659/*
660 * Replace kernel command line in a blob representing a kernel.
661 */
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +0800662static int ReplaceConfig(blob_t* bp, const char* config_file,
663 uint64_t kernel_body_load_address)
vbendebb2b0fcc2010-07-15 15:09:47 -0700664{
665 uint8_t* new_conf;
666 uint64_t config_size;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700667
vbendebb2b0fcc2010-07-15 15:09:47 -0700668 if (!config_file) {
669 return 0;
670 }
671
672 new_conf = ReadConfigFile(config_file, &config_size);
673 if (!new_conf) {
674 return 1;
675 }
676
677 /* fill the config buffer with zeros */
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +0800678 Memset(BpCmdLineLocation(bp, kernel_body_load_address), 0, CROS_CONFIG_SIZE);
679 Memcpy(BpCmdLineLocation(bp, kernel_body_load_address),
680 new_conf, config_size);
Randall Spangler32a65262011-06-27 10:49:11 -0700681 free(new_conf);
vbendebb2b0fcc2010-07-15 15:09:47 -0700682 return 0;
683}
684
Will Drewry9342f882010-10-26 10:22:05 -0500685static int Verify(const char* infile, const char* signpubkey, int verbose,
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +0800686 const char* key_block_file,
Randall Spangler7ecb39d2011-05-12 15:37:45 -0700687 uint64_t kernel_body_load_address, uint64_t min_version,
688 uint64_t pad) {
Randall Spangler7d6898d2010-06-11 09:22:13 -0700689
690 VbKeyBlockHeader* key_block;
691 VbKernelPreambleHeader* preamble;
692 VbPublicKey* data_key;
Bill Richardson4f36ef32010-08-09 17:50:14 -0700693 VbPublicKey* sign_key = NULL;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700694 RSAPublicKey* rsa;
vbendebb2b0fcc2010-07-15 15:09:47 -0700695 blob_t* bp;
696 uint64_t now;
697 int rv = 1;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700698
Bill Richardson4f36ef32010-08-09 17:50:14 -0700699 if (!infile) {
Randall Spangler32a65262011-06-27 10:49:11 -0700700 VbExError("Must specify filename\n");
Randall Spangler7d6898d2010-06-11 09:22:13 -0700701 return 1;
702 }
703
704 /* Read public signing key */
Bill Richardson4f36ef32010-08-09 17:50:14 -0700705 if (signpubkey) {
706 sign_key = PublicKeyRead(signpubkey);
707 if (!sign_key) {
Randall Spangler32a65262011-06-27 10:49:11 -0700708 VbExError("Error reading signpubkey.\n");
Bill Richardson4f36ef32010-08-09 17:50:14 -0700709 return 1;
710 }
Randall Spangler7d6898d2010-06-11 09:22:13 -0700711 }
712
713 /* Read blob */
Randall Spangler7ecb39d2011-05-12 15:37:45 -0700714 bp = OldBlob(infile, pad);
vbendebb2b0fcc2010-07-15 15:09:47 -0700715 if (!bp) {
Randall Spangler32a65262011-06-27 10:49:11 -0700716 VbExError("Error reading input file\n");
Randall Spangler7d6898d2010-06-11 09:22:13 -0700717 return 1;
718 }
719
720 /* Verify key block */
vbendebb2b0fcc2010-07-15 15:09:47 -0700721 key_block = bp->key_block;
Bill Richardsonbde06962012-03-15 10:00:41 -0700722 if (0 != KeyBlockVerify(key_block, key_block->key_block_size, sign_key,
Randall Spangler138acfe2010-08-17 15:45:21 -0700723 (sign_key ? 0 : 1))) {
Randall Spangler32a65262011-06-27 10:49:11 -0700724 VbExError("Error verifying key block.\n");
vbendebb2b0fcc2010-07-15 15:09:47 -0700725 goto verify_exit;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700726 }
vbendebb2b0fcc2010-07-15 15:09:47 -0700727 now = key_block->key_block_size;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700728
Will Drewry9342f882010-10-26 10:22:05 -0500729 if (key_block_file) {
730 FILE* f = NULL;
731 f = fopen(key_block_file, "wb");
732 if (!f) {
Randall Spangler32a65262011-06-27 10:49:11 -0700733 VbExError("Can't open key block file %s\n", key_block_file);
Will Drewry9342f882010-10-26 10:22:05 -0500734 return 1;
735 }
736 if (1 != fwrite(key_block, key_block->key_block_size, 1, f)) {
Randall Spangler32a65262011-06-27 10:49:11 -0700737 VbExError("Can't write key block file %s\n", key_block_file);
Will Drewry9342f882010-10-26 10:22:05 -0500738 return 1;
739 }
740 fclose(f);
741 }
742
Randall Spangler7d6898d2010-06-11 09:22:13 -0700743 printf("Key block:\n");
744 data_key = &key_block->data_key;
Bill Richardson4f36ef32010-08-09 17:50:14 -0700745 if (verbose)
746 printf(" Signature: %s\n", sign_key ? "valid" : "ignored");
Bill Richardsona08b5c92010-06-30 21:59:43 -0700747 printf(" Size: 0x%" PRIx64 "\n", key_block->key_block_size);
Bill Richardson60bcbe32010-09-09 14:53:56 -0700748 printf(" Flags: %" PRIu64 " ", key_block->key_block_flags);
749 if (key_block->key_block_flags & KEY_BLOCK_FLAG_DEVELOPER_0)
750 printf(" !DEV");
751 if (key_block->key_block_flags & KEY_BLOCK_FLAG_DEVELOPER_1)
752 printf(" DEV");
753 if (key_block->key_block_flags & KEY_BLOCK_FLAG_RECOVERY_0)
754 printf(" !REC");
755 if (key_block->key_block_flags & KEY_BLOCK_FLAG_RECOVERY_1)
756 printf(" REC");
757 printf("\n");
Randall Spangler7d6898d2010-06-11 09:22:13 -0700758 printf(" Data key algorithm: %" PRIu64 " %s\n", data_key->algorithm,
759 (data_key->algorithm < kNumAlgorithms ?
760 algo_strings[data_key->algorithm] : "(invalid)"));
761 printf(" Data key version: %" PRIu64 "\n", data_key->key_version);
Bill Richardson60bcbe32010-09-09 14:53:56 -0700762 printf(" Data key sha1sum: ");
763 PrintPubKeySha1Sum(data_key);
764 printf("\n");
Randall Spangler7d6898d2010-06-11 09:22:13 -0700765
Randall Spanglerae87b922011-05-12 13:27:28 -0700766 if (data_key->key_version < (min_version >> 16)) {
Randall Spangler32a65262011-06-27 10:49:11 -0700767 VbExError("Data key version %" PRIu64
768 " is lower than minimum %" PRIu64".\n",
769 data_key->key_version, (min_version >> 16));
Randall Spanglerae87b922011-05-12 13:27:28 -0700770 goto verify_exit;
771 }
772
Randall Spangler7d6898d2010-06-11 09:22:13 -0700773 rsa = PublicKeyToRSA(&key_block->data_key);
774 if (!rsa) {
Randall Spangler32a65262011-06-27 10:49:11 -0700775 VbExError("Error parsing data key.\n");
vbendebb2b0fcc2010-07-15 15:09:47 -0700776 goto verify_exit;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700777 }
778
779 /* Verify preamble */
vbendebb2b0fcc2010-07-15 15:09:47 -0700780 preamble = bp->preamble;
Bill Richardsonbde06962012-03-15 10:00:41 -0700781 if (0 != VerifyKernelPreamble(preamble, preamble->preamble_size, rsa)) {
Randall Spangler32a65262011-06-27 10:49:11 -0700782 VbExError("Error verifying preamble.\n");
vbendebb2b0fcc2010-07-15 15:09:47 -0700783 goto verify_exit;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700784 }
785 now += preamble->preamble_size;
786
787 printf("Preamble:\n");
Bill Richardsona08b5c92010-06-30 21:59:43 -0700788 printf(" Size: 0x%" PRIx64 "\n", preamble->preamble_size);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700789 printf(" Header version: %" PRIu32 ".%" PRIu32"\n",
790 preamble->header_version_major, preamble->header_version_minor);
791 printf(" Kernel version: %" PRIu64 "\n", preamble->kernel_version);
Bill Richardson249677d2010-06-23 11:16:37 -0700792 printf(" Body load address: 0x%" PRIx64 "\n", preamble->body_load_address);
793 printf(" Body size: 0x%" PRIx64 "\n",
Randall Spangler7d6898d2010-06-11 09:22:13 -0700794 preamble->body_signature.data_size);
Randall Spangler87c13d82010-07-19 10:35:40 -0700795 printf(" Bootloader address: 0x%" PRIx64 "\n",
796 preamble->bootloader_address);
Bill Richardson249677d2010-06-23 11:16:37 -0700797 printf(" Bootloader size: 0x%" PRIx64 "\n", preamble->bootloader_size);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700798
Randall Spanglerae87b922011-05-12 13:27:28 -0700799 if (preamble->kernel_version < (min_version & 0xFFFF)) {
Randall Spangler32a65262011-06-27 10:49:11 -0700800 VbExError("Kernel version %" PRIu64 " is lower than minimum %" PRIu64 ".\n",
801 preamble->kernel_version, (min_version & 0xFFFF));
Randall Spanglerae87b922011-05-12 13:27:28 -0700802 goto verify_exit;
803 }
804
Randall Spangler7d6898d2010-06-11 09:22:13 -0700805 /* Verify body */
Bill Richardsonc8b9ca62012-03-14 10:54:05 -0700806 if (0 != VerifyData(bp->kern_blob, bp->kern_blob_size,
807 &preamble->body_signature, rsa)) {
Randall Spangler32a65262011-06-27 10:49:11 -0700808 VbExError("Error verifying kernel body.\n");
vbendebb2b0fcc2010-07-15 15:09:47 -0700809 goto verify_exit;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700810 }
811 printf("Body verification succeeded.\n");
vbendebb2b0fcc2010-07-15 15:09:47 -0700812
813 rv = 0;
814
815 if (!verbose) {
816 goto verify_exit;
817 }
818
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +0800819 printf("Config:\n%s\n", BpCmdLineLocation(bp, kernel_body_load_address));
vbendebb2b0fcc2010-07-15 15:09:47 -0700820
821verify_exit:
822 FreeBlob(bp);
823 return rv;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700824}
825
826
827int main(int argc, char* argv[]) {
Randall Spangler7d6898d2010-06-11 09:22:13 -0700828 char* filename = NULL;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700829 char* oldfile = NULL;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700830 char* key_block_file = NULL;
831 char* signpubkey = NULL;
832 char* signprivate = NULL;
vbendeb00b90882010-10-21 13:46:16 -0700833 int version = -1;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700834 char* vmlinuz = NULL;
835 char* bootloader = NULL;
836 char* config_file = NULL;
Che-Liang Chiou03762032011-02-22 11:16:51 +0800837 int arch = ARCH_X86;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700838 int vblockonly = 0;
vbendebb2b0fcc2010-07-15 15:09:47 -0700839 int verbose = 0;
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +0800840 uint64_t kernel_body_load_address = CROS_32BIT_ENTRY_ADDR;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700841 uint64_t pad = DEFAULT_PADDING;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700842 int mode = 0;
843 int parse_error = 0;
Randall Spanglerae87b922011-05-12 13:27:28 -0700844 uint64_t min_version = 0;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700845 char* e;
Bill Richardsona08b5c92010-06-30 21:59:43 -0700846 int i,r;
847 blob_t *bp;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700848
Bill Richardsona08b5c92010-06-30 21:59:43 -0700849
850 char *progname = strrchr(argv[0], '/');
851 if (progname)
852 progname++;
853 else
854 progname = argv[0];
855
vbendebb2b0fcc2010-07-15 15:09:47 -0700856 while (((i = getopt_long(argc, argv, ":", long_opts, NULL)) != -1) &&
857 !parse_error) {
Randall Spangler7d6898d2010-06-11 09:22:13 -0700858 switch (i) {
vbendebb2b0fcc2010-07-15 15:09:47 -0700859 default:
Randall Spangler7d6898d2010-06-11 09:22:13 -0700860 case '?':
861 /* Unhandled option */
Randall Spangler7d6898d2010-06-11 09:22:13 -0700862 parse_error = 1;
863 break;
864
Bill Richardson4f36ef32010-08-09 17:50:14 -0700865 case 0:
866 /* silently handled option */
867 break;
868
Randall Spangler7d6898d2010-06-11 09:22:13 -0700869 case OPT_MODE_PACK:
Bill Richardsona08b5c92010-06-30 21:59:43 -0700870 case OPT_MODE_REPACK:
Randall Spangler7d6898d2010-06-11 09:22:13 -0700871 case OPT_MODE_VERIFY:
vbendebb2b0fcc2010-07-15 15:09:47 -0700872 if (mode && (mode != i)) {
873 fprintf(stderr, "Only single mode can be specified\n");
874 parse_error = 1;
875 break;
876 }
Randall Spangler7d6898d2010-06-11 09:22:13 -0700877 mode = i;
878 filename = optarg;
879 break;
880
Che-Liang Chiou03762032011-02-22 11:16:51 +0800881 case OPT_ARCH:
Sonny Rao06edfc62011-09-16 11:52:22 -0700882 /* check the first 3 characters to also detect x86_64 */
Sonny Rao74554732011-10-11 18:36:19 -0700883 if ((!strncasecmp(optarg, "x86", 3)) ||
884 (!strcasecmp(optarg, "amd64")))
Che-Liang Chiou03762032011-02-22 11:16:51 +0800885 arch = ARCH_X86;
886 else if (!strcasecmp(optarg, "arm"))
887 arch = ARCH_ARM;
888 else {
889 fprintf(stderr, "Unknown architecture string: %s\n", optarg);
890 parse_error = 1;
891 }
892 break;
893
Bill Richardsona08b5c92010-06-30 21:59:43 -0700894 case OPT_OLDBLOB:
895 oldfile = optarg;
896 break;
897
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +0800898 case OPT_KLOADADDR:
899 kernel_body_load_address = strtoul(optarg, &e, 0);
900 if (!*optarg || (e && *e)) {
901 fprintf(stderr, "Invalid --kloadaddr\n");
902 parse_error = 1;
903 }
904 break;
905
Randall Spangler7d6898d2010-06-11 09:22:13 -0700906 case OPT_KEYBLOCK:
907 key_block_file = optarg;
908 break;
909
910 case OPT_SIGNPUBKEY:
911 signpubkey = optarg;
912 break;
913
914 case OPT_SIGNPRIVATE:
915 signprivate = optarg;
916 break;
917
918 case OPT_VMLINUZ:
919 vmlinuz = optarg;
920 break;
921
922 case OPT_BOOTLOADER:
923 bootloader = optarg;
924 break;
925
926 case OPT_CONFIG:
927 config_file = optarg;
928 break;
929
Bill Richardsona08b5c92010-06-30 21:59:43 -0700930 case OPT_VBLOCKONLY:
931 vblockonly = 1;
932 break;
933
Randall Spangler7d6898d2010-06-11 09:22:13 -0700934 case OPT_VERSION:
935 version = strtoul(optarg, &e, 0);
936 if (!*optarg || (e && *e)) {
Bill Richardsona08b5c92010-06-30 21:59:43 -0700937 fprintf(stderr, "Invalid --version\n");
Randall Spangler7d6898d2010-06-11 09:22:13 -0700938 parse_error = 1;
939 }
940 break;
941
Randall Spanglerae87b922011-05-12 13:27:28 -0700942 case OPT_MINVERSION:
943 min_version = strtoul(optarg, &e, 0);
944 if (!*optarg || (e && *e)) {
945 fprintf(stderr, "Invalid --minversion\n");
946 parse_error = 1;
947 }
948 break;
949
Randall Spangler7d6898d2010-06-11 09:22:13 -0700950 case OPT_PAD:
951 pad = strtoul(optarg, &e, 0);
952 if (!*optarg || (e && *e)) {
Bill Richardsona08b5c92010-06-30 21:59:43 -0700953 fprintf(stderr, "Invalid --pad\n");
Randall Spangler7d6898d2010-06-11 09:22:13 -0700954 parse_error = 1;
955 }
956 break;
vbendebb2b0fcc2010-07-15 15:09:47 -0700957
958 case OPT_VERBOSE:
959 verbose = 1;
960 break;
Randall Spangler7d6898d2010-06-11 09:22:13 -0700961 }
962 }
963
964 if (parse_error)
Bill Richardsona08b5c92010-06-30 21:59:43 -0700965 return PrintHelp(progname);
Randall Spangler7d6898d2010-06-11 09:22:13 -0700966
967 switch(mode) {
968 case OPT_MODE_PACK:
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +0800969 bp = NewBlob(version, vmlinuz, bootloader, config_file, arch,
970 kernel_body_load_address);
Bill Richardsona08b5c92010-06-30 21:59:43 -0700971 if (!bp)
972 return 1;
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +0800973 r = Pack(filename, key_block_file, signprivate, bp, pad, vblockonly,
974 kernel_body_load_address);
Bill Richardsona08b5c92010-06-30 21:59:43 -0700975 FreeBlob(bp);
976 return r;
977
978 case OPT_MODE_REPACK:
vbendeb00b90882010-10-21 13:46:16 -0700979 if (!config_file && !key_block_file && (version<0)) {
vbendebb2b0fcc2010-07-15 15:09:47 -0700980 fprintf(stderr,
vbendeb858fffb2010-10-06 09:51:44 -0700981 "You must supply at least one of "
982 "--config, --keyblock or --version\n");
vbendebb2b0fcc2010-07-15 15:09:47 -0700983 return 1;
984 }
985
Randall Spangler7ecb39d2011-05-12 15:37:45 -0700986 bp = OldBlob(oldfile, pad);
Bill Richardsona08b5c92010-06-30 21:59:43 -0700987 if (!bp)
988 return 1;
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +0800989 r = ReplaceConfig(bp, config_file, kernel_body_load_address);
vbendebb2b0fcc2010-07-15 15:09:47 -0700990 if (!r) {
vbendeb00b90882010-10-21 13:46:16 -0700991 if (version >= 0) {
Che-Liang Chiou03762032011-02-22 11:16:51 +0800992 bp->kernel_version = (uint64_t) version;
vbendeb858fffb2010-10-06 09:51:44 -0700993 }
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +0800994 r = Pack(filename, key_block_file, signprivate, bp, pad, vblockonly,
995 kernel_body_load_address);
vbendebb2b0fcc2010-07-15 15:09:47 -0700996 }
Bill Richardsona08b5c92010-06-30 21:59:43 -0700997 FreeBlob(bp);
998 return r;
999
Randall Spangler7d6898d2010-06-11 09:22:13 -07001000 case OPT_MODE_VERIFY:
Che-Liang Chiou2c0711b2011-03-22 13:15:19 +08001001 return Verify(filename, signpubkey, verbose, key_block_file,
Randall Spangler7ecb39d2011-05-12 15:37:45 -07001002 kernel_body_load_address, min_version, pad);
Bill Richardsona08b5c92010-06-30 21:59:43 -07001003
Randall Spangler7d6898d2010-06-11 09:22:13 -07001004 default:
Bill Richardsona08b5c92010-06-30 21:59:43 -07001005 fprintf(stderr,
1006 "You must specify a mode: --pack, --repack or --verify\n");
1007 return PrintHelp(progname);
Randall Spangler7d6898d2010-06-11 09:22:13 -07001008 }
1009}