OLD | NEW |
1 /* Copyright (c) 2010 The Chromium OS Authors. All rights reserved. | 1 /* Copyright (c) 2010 The Chromium OS Authors. All rights reserved. |
2 * Use of this source code is governed by a BSD-style license that can be | 2 * Use of this source code is governed by a BSD-style license that can be |
3 * found in the LICENSE file. | 3 * found in the LICENSE file. |
4 * | 4 * |
5 * Verified boot kernel utility | 5 * Verified boot kernel utility |
6 */ | 6 */ |
7 | 7 |
| 8 #include <errno.h> |
8 #include <getopt.h> | 9 #include <getopt.h> |
9 #include <inttypes.h> /* For PRIu64 */ | 10 #include <inttypes.h> /* For PRIu64 */ |
10 #include <stdarg.h> | 11 #include <stdarg.h> |
11 #include <stddef.h> | 12 #include <stddef.h> |
12 #include <stdio.h> | 13 #include <stdio.h> |
13 #include <stdlib.h> | 14 #include <stdlib.h> |
| 15 #include <string.h> |
| 16 #include <sys/stat.h> |
| 17 #include <sys/types.h> |
14 #include <unistd.h> | 18 #include <unistd.h> |
15 | 19 |
16 #include "cryptolib.h" | 20 #include "cryptolib.h" |
17 #include "host_common.h" | 21 #include "host_common.h" |
18 #include "kernel_blob.h" | 22 #include "kernel_blob.h" |
19 #include "vboot_common.h" | 23 #include "vboot_common.h" |
20 | 24 |
21 | 25 |
22 /* Global opt */ | 26 /* Global opt */ |
23 static int opt_debug = 0; | 27 static int opt_debug = 0; |
24 | 28 |
| 29 static const int DEFAULT_PADDING = 65536; |
25 | 30 |
26 /* Command line options */ | 31 /* Command line options */ |
27 enum { | 32 enum { |
28 OPT_MODE_PACK = 1000, | 33 OPT_MODE_PACK = 1000, |
| 34 OPT_MODE_REPACK, |
29 OPT_MODE_VERIFY, | 35 OPT_MODE_VERIFY, |
| 36 OPT_OLDBLOB, |
30 OPT_KEYBLOCK, | 37 OPT_KEYBLOCK, |
31 OPT_SIGNPUBKEY, | 38 OPT_SIGNPUBKEY, |
32 OPT_SIGNPRIVATE, | 39 OPT_SIGNPRIVATE, |
33 OPT_VERSION, | 40 OPT_VERSION, |
34 OPT_VMLINUZ, | 41 OPT_VMLINUZ, |
35 OPT_BOOTLOADER, | 42 OPT_BOOTLOADER, |
36 OPT_CONFIG, | 43 OPT_CONFIG, |
| 44 OPT_VBLOCKONLY, |
37 OPT_PAD, | 45 OPT_PAD, |
38 }; | 46 }; |
39 | 47 |
40 static struct option long_opts[] = { | 48 static struct option long_opts[] = { |
41 {"pack", 1, 0, OPT_MODE_PACK }, | 49 {"pack", 1, 0, OPT_MODE_PACK }, |
| 50 {"repack", 1, 0, OPT_MODE_REPACK }, |
42 {"verify", 1, 0, OPT_MODE_VERIFY }, | 51 {"verify", 1, 0, OPT_MODE_VERIFY }, |
| 52 {"oldblob", 1, 0, OPT_OLDBLOB }, |
43 {"keyblock", 1, 0, OPT_KEYBLOCK }, | 53 {"keyblock", 1, 0, OPT_KEYBLOCK }, |
44 {"signpubkey", 1, 0, OPT_SIGNPUBKEY }, | 54 {"signpubkey", 1, 0, OPT_SIGNPUBKEY }, |
45 {"signprivate", 1, 0, OPT_SIGNPRIVATE }, | 55 {"signprivate", 1, 0, OPT_SIGNPRIVATE }, |
46 {"version", 1, 0, OPT_VERSION }, | 56 {"version", 1, 0, OPT_VERSION }, |
47 {"vmlinuz", 1, 0, OPT_VMLINUZ }, | 57 {"vmlinuz", 1, 0, OPT_VMLINUZ }, |
48 {"bootloader", 1, 0, OPT_BOOTLOADER }, | 58 {"bootloader", 1, 0, OPT_BOOTLOADER }, |
49 {"config", 1, 0, OPT_CONFIG }, | 59 {"config", 1, 0, OPT_CONFIG }, |
| 60 {"vblockonly", 0, 0, OPT_VBLOCKONLY }, |
50 {"pad", 1, 0, OPT_PAD }, | 61 {"pad", 1, 0, OPT_PAD }, |
51 {"debug", 0, &opt_debug, 1 }, | 62 {"debug", 0, &opt_debug, 1 }, |
52 {NULL, 0, 0, 0} | 63 {NULL, 0, 0, 0} |
53 }; | 64 }; |
54 | 65 |
55 | 66 |
56 /* Print help and return error */ | 67 /* Print help and return error */ |
57 static int PrintHelp(void) { | 68 static int PrintHelp(char *progname) { |
58 | 69 fprintf(stderr, |
59 puts("vbutil_kernel - Verified boot key block utility\n" | 70 "This program creates, signs, and verifies the kernel blob\n"); |
60 "\n" | 71 fprintf(stderr, |
61 "Usage: vbutil_kernel <--pack|--verify> <file> [OPTIONS]\n" | 72 "\n" |
62 "\n" | 73 "Usage: %s --pack <file> [PARAMETERS]\n" |
63 "For '--pack <file>', required OPTIONS are:\n" | 74 "\n" |
64 " --keyblock <file> Key block in .keyblock format\n" | 75 " Required parameters:\n" |
65 " --signprivate <file> Signing private key in .pem format\n" | 76 " --keyblock <file> Key block in .keyblock format\n" |
66 " --version <number> Kernel version\n" | 77 " --signprivate <file> Signing private key in .pem format\n" |
67 " --vmlinuz <file> Linux kernel image\n" | 78 " --version <number> Kernel version\n" |
68 " --bootloader <file> Bootloader stub\n" | 79 " --vmlinuz <file> Linux kernel bzImage file\n" |
69 " --config <file> Config file\n" | 80 " --bootloader <file> Bootloader stub\n" |
70 "Optional OPTIONS are:\n" | 81 " --config <file> Config file\n" |
71 " --pad <number> Padding size in bytes\n" | 82 "\n" |
72 "\n" | 83 " Optional:\n" |
73 "For '--verify <file>', required OPTIONS are:\n" | 84 " --pad <number> Verification padding size in bytes\n" |
74 " --signpubkey <file> Signing public key in .vbpubk format\n" | 85 " --vblockonly Emit just the verification blob\n", |
75 ""); | 86 progname); |
| 87 fprintf(stderr, |
| 88 "\nOR\n\n" |
| 89 "Usage: %s --repack <file> [PARAMETERS]\n" |
| 90 "\n" |
| 91 " Required parameters:\n" |
| 92 " --keyblock <file> Key block in .keyblock format\n" |
| 93 " --signprivate <file> Signing private key in .pem format\n" |
| 94 " --oldblob <file> Previously packed kernel blob\n" |
| 95 "\n" |
| 96 " Optional:\n" |
| 97 " --pad <number> Verification padding size in bytes\n" |
| 98 " --vblockonly Emit just the verification blob\n", |
| 99 progname); |
| 100 fprintf(stderr, |
| 101 "\nOR\n\n" |
| 102 "Usage: %s --verify <file> [PARAMETERS]\n" |
| 103 "\n" |
| 104 " Required parameters:\n" |
| 105 " --signpubkey <file> Signing public key in .vbpubk format\n" |
| 106 "\n", |
| 107 progname); |
76 return 1; | 108 return 1; |
77 } | 109 } |
78 | 110 |
79 static void Debug(const char *format, ...) { | 111 static void Debug(const char *format, ...) { |
80 if (!opt_debug) | 112 if (!opt_debug) |
81 return; | 113 return; |
82 | 114 |
83 va_list ap; | 115 va_list ap; |
84 va_start(ap, format); | 116 va_start(ap, format); |
85 fprintf(stderr, "DEBUG: "); | 117 fprintf(stderr, "DEBUG: "); |
(...skipping 28 matching lines...) Expand all Loading... |
114 } | 146 } |
115 } | 147 } |
116 } | 148 } |
117 while(' ' == input[start]) /* skip leading spaces */ | 149 while(' ' == input[start]) /* skip leading spaces */ |
118 start++; | 150 start++; |
119 | 151 |
120 return start; | 152 return start; |
121 } | 153 } |
122 | 154 |
123 | 155 |
124 /* Pack a .kernel */ | 156 typedef struct blob_s { |
125 static int Pack(const char* outfile, const char* keyblock_file, | 157 /* Stuff needed by VbKernelPreambleHeader */ |
126 const char* signprivate, uint64_t version, | 158 uint64_t kernel_version; |
127 const char* vmlinuz, const char* bootloader_file, | 159 uint64_t bootloader_address; |
128 const char* config_file, uint64_t pad) { | 160 uint64_t bootloader_size; |
| 161 /* Raw kernel blob data */ |
| 162 uint64_t blob_size; |
| 163 uint8_t *blob; |
| 164 } blob_t; |
129 | 165 |
| 166 |
| 167 static void FreeBlob(blob_t *bp) { |
| 168 if (bp) { |
| 169 if (bp->blob) |
| 170 Free(bp->blob); |
| 171 Free(bp); |
| 172 } |
| 173 } |
| 174 |
| 175 /* Create a blob from its components */ |
| 176 static blob_t *NewBlob(uint64_t version, |
| 177 const char* vmlinuz, |
| 178 const char* bootloader_file, |
| 179 const char* config_file) { |
| 180 blob_t *bp; |
130 struct linux_kernel_header *lh = 0; | 181 struct linux_kernel_header *lh = 0; |
131 struct linux_kernel_params *params = 0; | 182 struct linux_kernel_params *params = 0; |
132 VbPrivateKey* signing_key; | |
133 VbSignature* body_sig; | |
134 VbKernelPreambleHeader* preamble; | |
135 VbKeyBlockHeader* key_block; | |
136 uint64_t key_block_size; | |
137 uint8_t* config_buf; | 183 uint8_t* config_buf; |
138 uint64_t config_size; | 184 uint64_t config_size; |
139 uint8_t* bootloader_buf; | 185 uint8_t* bootloader_buf; |
140 uint64_t bootloader_size; | 186 uint64_t bootloader_size; |
141 uint64_t bootloader_mem_start; | |
142 uint64_t bootloader_mem_size; | |
143 uint8_t* kernel_buf; | 187 uint8_t* kernel_buf; |
144 uint64_t kernel_size; | 188 uint64_t kernel_size; |
145 uint64_t kernel32_start = 0; | 189 uint64_t kernel32_start = 0; |
146 uint64_t kernel32_size = 0; | 190 uint64_t kernel32_size = 0; |
147 uint32_t cmdline_addr; | 191 uint32_t cmdline_addr; |
148 uint8_t* blob = NULL; | 192 uint8_t* blob = NULL; |
149 uint64_t blob_size; | |
150 uint64_t now = 0; | 193 uint64_t now = 0; |
151 FILE* f; | |
152 uint64_t i; | 194 uint64_t i; |
153 | 195 |
154 if (!outfile) { | |
155 error("Must specify output filename\n"); | |
156 return 1; | |
157 } | |
158 if (!keyblock_file || !signprivate) { | |
159 error("Must specify all keys\n"); | |
160 return 1; | |
161 } | |
162 if (!vmlinuz || !bootloader_file || !config_file) { | 196 if (!vmlinuz || !bootloader_file || !config_file) { |
163 error("Must specify all input files\n"); | 197 error("Must specify all input files\n"); |
164 return 1; | 198 return 0; |
165 } | 199 } |
166 | 200 |
167 /* Read the key block and private key */ | 201 bp = (blob_t *)Malloc(sizeof(blob_t)); |
168 key_block = (VbKeyBlockHeader*)ReadFile(keyblock_file, &key_block_size); | 202 if (!bp) { |
169 if (!key_block) { | 203 error("Couldn't allocate bytes for blob_t.\n"); |
170 error("Error reading key block.\n"); | 204 return 0; |
171 return 1; | |
172 } | 205 } |
173 if (pad < key_block->key_block_size) { | 206 bp->kernel_version = version; |
174 error("Pad too small\n"); | |
175 return 1; | |
176 } | |
177 | |
178 signing_key = PrivateKeyRead(signprivate, key_block->data_key.algorithm); | |
179 if (!signing_key) { | |
180 error("Error reading signing key.\n"); | |
181 return 1; | |
182 } | |
183 | 207 |
184 /* Read the config file */ | 208 /* Read the config file */ |
185 Debug("Reading %s\n", config_file); | 209 Debug("Reading %s\n", config_file); |
186 config_buf = ReadFile(config_file, &config_size); | 210 config_buf = ReadFile(config_file, &config_size); |
187 if (!config_buf) | 211 if (!config_buf) |
188 return 1; | 212 return 0; |
189 Debug(" config file size=0x%" PRIx64 "\n", config_size); | 213 Debug(" config file size=0x%" PRIx64 "\n", config_size); |
190 if (CROS_CONFIG_SIZE <= config_size) { /* need room for trailing '\0' */ | 214 if (CROS_CONFIG_SIZE <= config_size) { /* need room for trailing '\0' */ |
191 error("Config file %s is too large (>= %d bytes)\n", | 215 error("Config file %s is too large (>= %d bytes)\n", |
192 config_file, CROS_CONFIG_SIZE); | 216 config_file, CROS_CONFIG_SIZE); |
193 return 1; | 217 return 0; |
194 } | 218 } |
195 /* Replace newlines with spaces */ | 219 /* Replace newlines with spaces */ |
196 for (i = 0; i < config_size; i++) | 220 for (i = 0; i < config_size; i++) |
197 if ('\n' == config_buf[i]) | 221 if ('\n' == config_buf[i]) |
198 config_buf[i] = ' '; | 222 config_buf[i] = ' '; |
199 | 223 |
200 /* Read the bootloader */ | 224 /* Read the bootloader */ |
201 Debug("Reading %s\n", bootloader_file); | 225 Debug("Reading %s\n", bootloader_file); |
202 bootloader_buf = ReadFile(bootloader_file, &bootloader_size); | 226 bootloader_buf = ReadFile(bootloader_file, &bootloader_size); |
203 if (!bootloader_buf) | 227 if (!bootloader_buf) |
204 return 1; | 228 return 0; |
205 Debug(" bootloader file size=0x%" PRIx64 "\n", bootloader_size); | 229 Debug(" bootloader file size=0x%" PRIx64 "\n", bootloader_size); |
206 | 230 |
207 /* Read the kernel */ | 231 /* Read the kernel */ |
208 Debug("Reading %s\n", vmlinuz); | 232 Debug("Reading %s\n", vmlinuz); |
209 kernel_buf = ReadFile(vmlinuz, &kernel_size); | 233 kernel_buf = ReadFile(vmlinuz, &kernel_size); |
210 if (!kernel_buf) | 234 if (!kernel_buf) |
211 return 1; | 235 return 0; |
212 Debug(" kernel file size=0x%" PRIx64 "\n", kernel_size); | 236 Debug(" kernel file size=0x%" PRIx64 "\n", kernel_size); |
213 if (!kernel_size) { | 237 if (!kernel_size) { |
214 error("Empty kernel file\n"); | 238 error("Empty kernel file\n"); |
215 return 1; | 239 return 0; |
216 } | 240 } |
217 | 241 |
218 /* The first part of vmlinuz is a header, followed by a real-mode | 242 /* The first part of vmlinuz is a header, followed by a real-mode |
219 * boot stub. We only want the 32-bit part. */ | 243 * boot stub. We only want the 32-bit part. */ |
220 lh = (struct linux_kernel_header *)kernel_buf; | 244 lh = (struct linux_kernel_header *)kernel_buf; |
221 kernel32_start = (lh->setup_sects + 1) << 9; | 245 kernel32_start = (lh->setup_sects + 1) << 9; |
222 if (kernel32_start >= kernel_size) { | 246 if (kernel32_start >= kernel_size) { |
223 error("Malformed kernel\n"); | 247 error("Malformed kernel\n"); |
224 return 1; | 248 return 0; |
225 } | 249 } |
226 kernel32_size = kernel_size - kernel32_start; | 250 kernel32_size = kernel_size - kernel32_start; |
227 Debug(" kernel32_start=0x%" PRIx64 "\n", kernel32_start); | 251 Debug(" kernel32_start=0x%" PRIx64 "\n", kernel32_start); |
228 Debug(" kernel32_size=0x%" PRIx64 "\n", kernel32_size); | 252 Debug(" kernel32_size=0x%" PRIx64 "\n", kernel32_size); |
229 | 253 |
230 /* Allocate and zero the blob we need. */ | 254 /* Allocate and zero the blob we need. */ |
231 blob_size = roundup(kernel32_size, CROS_ALIGN) + | 255 bp->blob_size = roundup(kernel32_size, CROS_ALIGN) + |
232 CROS_CONFIG_SIZE + | 256 CROS_CONFIG_SIZE + |
233 CROS_PARAMS_SIZE + | 257 CROS_PARAMS_SIZE + |
234 roundup(bootloader_size, CROS_ALIGN); | 258 roundup(bootloader_size, CROS_ALIGN); |
235 blob = (uint8_t *)Malloc(blob_size); | 259 blob = (uint8_t *)Malloc(bp->blob_size); |
236 Debug("blob_size=0x%" PRIx64 "\n", blob_size); | 260 Debug("blob_size=0x%" PRIx64 "\n", bp->blob_size); |
237 if (!blob) { | 261 if (!blob) { |
238 error("Couldn't allocate %ld bytes.\n", blob_size); | 262 error("Couldn't allocate %ld bytes.\n", bp->blob_size); |
239 return 1; | 263 return 0; |
240 } | 264 } |
241 Memset(blob, 0, blob_size); | 265 Memset(blob, 0, bp->blob_size); |
| 266 bp->blob = blob; |
242 | 267 |
243 /* Copy the 32-bit kernel. */ | 268 /* Copy the 32-bit kernel. */ |
244 Debug("kernel goes at blob+=0x%" PRIx64 "\n", now); | 269 Debug("kernel goes at blob+=0x%" PRIx64 "\n", now); |
245 if (kernel32_size) | 270 if (kernel32_size) |
246 Memcpy(blob + now, kernel_buf + kernel32_start, kernel32_size); | 271 Memcpy(blob + now, kernel_buf + kernel32_start, kernel32_size); |
247 now += roundup(now + kernel32_size, CROS_ALIGN); | 272 now += roundup(now + kernel32_size, CROS_ALIGN); |
248 | 273 |
249 Debug("config goes at blob+0x%" PRIx64 "\n", now); | 274 Debug("config goes at blob+0x%" PRIx64 "\n", now); |
250 /* Find the load address of the commandline. We'll need it later. */ | 275 /* Find the load address of the commandline. We'll need it later. */ |
251 cmdline_addr = CROS_32BIT_ENTRY_ADDR + now + | 276 cmdline_addr = CROS_32BIT_ENTRY_ADDR + now + |
(...skipping 14 matching lines...) Expand all Loading... |
266 params->boot_flag = 0; | 291 params->boot_flag = 0; |
267 params->ramdisk_image = 0; /* we don't support initrd */ | 292 params->ramdisk_image = 0; /* we don't support initrd */ |
268 params->ramdisk_size = 0; | 293 params->ramdisk_size = 0; |
269 params->type_of_loader = 0xff; | 294 params->type_of_loader = 0xff; |
270 params->cmd_line_ptr = cmdline_addr; | 295 params->cmd_line_ptr = cmdline_addr; |
271 now += CROS_PARAMS_SIZE; | 296 now += CROS_PARAMS_SIZE; |
272 | 297 |
273 /* Finally, append the bootloader. Remember where it will load in | 298 /* Finally, append the bootloader. Remember where it will load in |
274 * memory, too. */ | 299 * memory, too. */ |
275 Debug("bootloader goes at blob+=0x%" PRIx64 "\n", now); | 300 Debug("bootloader goes at blob+=0x%" PRIx64 "\n", now); |
276 bootloader_mem_start = CROS_32BIT_ENTRY_ADDR + now; | 301 bp->bootloader_address = CROS_32BIT_ENTRY_ADDR + now; |
277 bootloader_mem_size = roundup(bootloader_size, CROS_ALIGN); | 302 bp->bootloader_size = roundup(bootloader_size, CROS_ALIGN); |
278 Debug(" bootloader_mem_start=0x%" PRIx64 "\n", bootloader_mem_start); | 303 Debug(" bootloader_address=0x%" PRIx64 "\n", bp->bootloader_address); |
279 Debug(" bootloader_mem_size=0x%" PRIx64 "\n", bootloader_mem_size); | 304 Debug(" bootloader_size=0x%" PRIx64 "\n", bp->bootloader_size); |
280 if (bootloader_size) | 305 if (bootloader_size) |
281 Memcpy(blob + now, bootloader_buf, bootloader_size); | 306 Memcpy(blob + now, bootloader_buf, bootloader_size); |
282 now += bootloader_mem_size; | 307 now += bp->bootloader_size; |
283 Debug("end of blob is 0x%" PRIx64 "\n", now); | 308 Debug("end of blob is 0x%" PRIx64 "\n", now); |
284 | 309 |
285 /* Free input buffers */ | 310 /* Free input buffers */ |
286 Free(kernel_buf); | 311 Free(kernel_buf); |
287 Free(config_buf); | 312 Free(config_buf); |
288 Free(bootloader_buf); | 313 Free(bootloader_buf); |
289 | 314 |
| 315 /* Success */ |
| 316 return bp; |
| 317 } |
| 318 |
| 319 |
| 320 /* Pull the blob_t stuff out of a prepacked kernel blob file */ |
| 321 static blob_t *OldBlob(const char* filename) { |
| 322 FILE* fp; |
| 323 blob_t *bp; |
| 324 struct stat statbuf; |
| 325 VbKeyBlockHeader* key_block; |
| 326 VbKernelPreambleHeader* preamble; |
| 327 uint64_t now = 0; |
| 328 uint8_t buf[DEFAULT_PADDING]; |
| 329 |
| 330 if (!filename) { |
| 331 error("Must specify prepacked blob to read\n"); |
| 332 return 0; |
| 333 } |
| 334 |
| 335 if (0 != stat(filename, &statbuf)) { |
| 336 error("unable to stat %s: %s\n", filename, strerror(errno)); |
| 337 return 0; |
| 338 } |
| 339 |
| 340 Debug("%s size is 0x%" PRIx64 "\n", filename, statbuf.st_size); |
| 341 if (statbuf.st_size < DEFAULT_PADDING) { |
| 342 error("%s is too small to be a valid kernel blob\n"); |
| 343 return 0; |
| 344 } |
| 345 |
| 346 Debug("Reading %s\n", filename); |
| 347 fp = fopen(filename, "rb"); |
| 348 if (!fp) { |
| 349 error("Unable to open file %s: %s\n", filename, strerror(errno)); |
| 350 return 0; |
| 351 } |
| 352 |
| 353 if (1 != fread(buf, sizeof(buf), 1, fp)) { |
| 354 error("Unable to read header from %s: %s\n", filename, strerror(errno)); |
| 355 fclose(fp); |
| 356 return 0; |
| 357 } |
| 358 |
| 359 /* Skip the key block */ |
| 360 key_block = (VbKeyBlockHeader*)buf; |
| 361 Debug("Keyblock is 0x%" PRIx64 " bytes\n", key_block->key_block_size); |
| 362 now += key_block->key_block_size; |
| 363 if (now > statbuf.st_size) { |
| 364 error("key_block_size advances past the end of the blob\n"); |
| 365 return 0; |
| 366 } |
| 367 |
| 368 /* Skip the preamble */ |
| 369 preamble = (VbKernelPreambleHeader*)(buf + now); |
| 370 Debug("Preamble is 0x%" PRIx64 " bytes\n", preamble->preamble_size); |
| 371 now += preamble->preamble_size; |
| 372 if (now > statbuf.st_size) { |
| 373 error("preamble_size advances past the end of the blob\n"); |
| 374 return 0; |
| 375 } |
| 376 |
| 377 /* Go find the kernel blob */ |
| 378 Debug("kernel blob is at offset 0x%" PRIx64 "\n", now); |
| 379 if (0 != fseek(fp, now, SEEK_SET)) { |
| 380 error("Unable to seek to 0x%" PRIx64 " in %s: %s\n", now, filename, |
| 381 strerror(errno)); |
| 382 fclose(fp); |
| 383 return 0; |
| 384 } |
| 385 |
| 386 /* Remember what we've got */ |
| 387 bp = (blob_t *)Malloc(sizeof(blob_t)); |
| 388 if (!bp) { |
| 389 error("Couldn't allocate bytes for blob_t.\n"); |
| 390 fclose(fp); |
| 391 return 0; |
| 392 } |
| 393 |
| 394 bp->kernel_version = preamble->kernel_version; |
| 395 bp->bootloader_address = preamble->bootloader_address; |
| 396 bp->bootloader_size = preamble->bootloader_size; |
| 397 bp->blob_size = preamble->body_signature.data_size; |
| 398 |
| 399 Debug(" kernel_version = %d\n", bp->kernel_version); |
| 400 Debug(" bootloader_address = 0x%" PRIx64 "\n", bp->bootloader_address); |
| 401 Debug(" bootloader_size = 0x%" PRIx64 "\n", bp->bootloader_size); |
| 402 Debug(" blob_size = 0x%" PRIx64 "\n", bp->blob_size); |
| 403 |
| 404 bp->blob = (uint8_t *)Malloc(bp->blob_size); |
| 405 if (!bp->blob) { |
| 406 error("Couldn't allocate 0x%" PRIx64 " bytes for blob_t.\n", bp->blob_size); |
| 407 fclose(fp); |
| 408 Free(bp); |
| 409 return 0; |
| 410 } |
| 411 |
| 412 /* read it in */ |
| 413 if (1 != fread(bp->blob, bp->blob_size, 1, fp)) { |
| 414 error("Unable to read kernel blob from %s: %s\n", filename, strerror(errno))
; |
| 415 fclose(fp); |
| 416 Free(bp); |
| 417 return 0; |
| 418 } |
| 419 |
| 420 /* done */ |
| 421 fclose(fp); |
| 422 |
| 423 return bp; |
| 424 } |
| 425 |
| 426 |
| 427 /* Pack a .kernel */ |
| 428 static int Pack(const char* outfile, const char* keyblock_file, |
| 429 const char* signprivate, blob_t *bp, uint64_t pad, |
| 430 int vblockonly) { |
| 431 VbPrivateKey* signing_key; |
| 432 VbSignature* body_sig; |
| 433 VbKernelPreambleHeader* preamble; |
| 434 VbKeyBlockHeader* key_block; |
| 435 uint64_t key_block_size; |
| 436 FILE* f; |
| 437 uint64_t i; |
| 438 |
| 439 if (!outfile) { |
| 440 error("Must specify output filename\n"); |
| 441 return 1; |
| 442 } |
| 443 if (!keyblock_file || !signprivate) { |
| 444 error("Must specify all keys\n"); |
| 445 return 1; |
| 446 } |
| 447 if (!bp) { |
| 448 error("Refusing to pack invalid kernel blob\n"); |
| 449 return 1; |
| 450 } |
| 451 |
| 452 /* Read the key block and private key */ |
| 453 key_block = (VbKeyBlockHeader*)ReadFile(keyblock_file, &key_block_size); |
| 454 if (!key_block) { |
| 455 error("Error reading key block.\n"); |
| 456 return 1; |
| 457 } |
| 458 if (pad < key_block->key_block_size) { |
| 459 error("Pad too small\n"); |
| 460 return 1; |
| 461 } |
| 462 |
| 463 signing_key = PrivateKeyReadPem(signprivate, key_block->data_key.algorithm); |
| 464 if (!signing_key) { |
| 465 error("Error reading signing key.\n"); |
| 466 return 1; |
| 467 } |
| 468 |
290 /* Sign the kernel data */ | 469 /* Sign the kernel data */ |
291 body_sig = CalculateSignature(blob, blob_size, signing_key); | 470 body_sig = CalculateSignature(bp->blob, bp->blob_size, signing_key); |
292 if (!body_sig) { | 471 if (!body_sig) { |
293 error("Error calculating body signature\n"); | 472 error("Error calculating body signature\n"); |
294 return 1; | 473 return 1; |
295 } | 474 } |
296 | 475 |
297 /* Create preamble */ | 476 /* Create preamble */ |
298 preamble = CreateKernelPreamble(version, | 477 preamble = CreateKernelPreamble(bp->kernel_version, |
299 CROS_32BIT_ENTRY_ADDR, | 478 CROS_32BIT_ENTRY_ADDR, |
300 bootloader_mem_start, | 479 bp->bootloader_address, |
301 bootloader_mem_size, | 480 bp->bootloader_size, |
302 body_sig, | 481 body_sig, |
303 pad - key_block_size, | 482 pad - key_block_size, |
304 signing_key); | 483 signing_key); |
305 if (!preamble) { | 484 if (!preamble) { |
306 error("Error creating preamble.\n"); | 485 error("Error creating preamble.\n"); |
307 return 1; | 486 return 1; |
308 } | 487 } |
309 | 488 |
310 /* Write the output file */ | 489 /* Write the output file */ |
311 Debug("writing %s...\n", outfile); | 490 Debug("writing %s...\n", outfile); |
312 f = fopen(outfile, "wb"); | 491 f = fopen(outfile, "wb"); |
313 if (!f) { | 492 if (!f) { |
314 error("Can't open output file %s\n", outfile); | 493 error("Can't open output file %s\n", outfile); |
315 return 1; | 494 return 1; |
316 } | 495 } |
317 Debug("0x%" PRIx64 " bytes of key_block\n", key_block_size); | 496 Debug("0x%" PRIx64 " bytes of key_block\n", key_block_size); |
318 Debug("0x%" PRIx64 " bytes of preamble\n", preamble->preamble_size); | 497 Debug("0x%" PRIx64 " bytes of preamble\n", preamble->preamble_size); |
319 Debug("0x%" PRIx64 " bytes of blob\n", blob_size); | |
320 i = ((1 != fwrite(key_block, key_block_size, 1, f)) || | 498 i = ((1 != fwrite(key_block, key_block_size, 1, f)) || |
321 (1 != fwrite(preamble, preamble->preamble_size, 1, f)) || | 499 (1 != fwrite(preamble, preamble->preamble_size, 1, f))); |
322 (1 != fwrite(blob, blob_size, 1, f))); | |
323 fclose(f); | |
324 if (i) { | 500 if (i) { |
325 error("Can't write output file %s\n", outfile); | 501 error("Can't write output file %s\n", outfile); |
| 502 fclose(f); |
326 unlink(outfile); | 503 unlink(outfile); |
327 return 1; | 504 return 1; |
328 } | 505 } |
329 | 506 |
| 507 if (!vblockonly) { |
| 508 Debug("0x%" PRIx64 " bytes of blob\n", bp->blob_size); |
| 509 i = (1 != fwrite(bp->blob, bp->blob_size, 1, f)); |
| 510 if (i) { |
| 511 error("Can't write output file %s\n", outfile); |
| 512 fclose(f); |
| 513 unlink(outfile); |
| 514 return 1; |
| 515 } |
| 516 } |
| 517 |
| 518 fclose(f); |
| 519 |
330 /* Success */ | 520 /* Success */ |
331 return 0; | 521 return 0; |
332 } | 522 } |
333 | 523 |
334 | 524 |
335 static int Verify(const char* infile, const char* signpubkey) { | 525 static int Verify(const char* infile, const char* signpubkey) { |
336 | 526 |
337 VbKeyBlockHeader* key_block; | 527 VbKeyBlockHeader* key_block; |
338 VbKernelPreambleHeader* preamble; | 528 VbKernelPreambleHeader* preamble; |
339 VbPublicKey* data_key; | 529 VbPublicKey* data_key; |
(...skipping 26 matching lines...) Expand all Loading... |
366 key_block = (VbKeyBlockHeader*)blob; | 556 key_block = (VbKeyBlockHeader*)blob; |
367 if (0 != KeyBlockVerify(key_block, blob_size, sign_key)) { | 557 if (0 != KeyBlockVerify(key_block, blob_size, sign_key)) { |
368 error("Error verifying key block.\n"); | 558 error("Error verifying key block.\n"); |
369 return 1; | 559 return 1; |
370 } | 560 } |
371 Free(sign_key); | 561 Free(sign_key); |
372 now += key_block->key_block_size; | 562 now += key_block->key_block_size; |
373 | 563 |
374 printf("Key block:\n"); | 564 printf("Key block:\n"); |
375 data_key = &key_block->data_key; | 565 data_key = &key_block->data_key; |
376 printf(" Size: %" PRIu64 "\n", key_block->key_block_size); | 566 printf(" Size: 0x%" PRIx64 "\n", key_block->key_block_size); |
377 printf(" Data key algorithm: %" PRIu64 " %s\n", data_key->algorithm, | 567 printf(" Data key algorithm: %" PRIu64 " %s\n", data_key->algorithm, |
378 (data_key->algorithm < kNumAlgorithms ? | 568 (data_key->algorithm < kNumAlgorithms ? |
379 algo_strings[data_key->algorithm] : "(invalid)")); | 569 algo_strings[data_key->algorithm] : "(invalid)")); |
380 printf(" Data key version: %" PRIu64 "\n", data_key->key_version); | 570 printf(" Data key version: %" PRIu64 "\n", data_key->key_version); |
381 printf(" Flags: %" PRIu64 "\n", key_block->key_block_flags); | 571 printf(" Flags: %" PRIu64 "\n", key_block->key_block_flags); |
382 | 572 |
383 rsa = PublicKeyToRSA(&key_block->data_key); | 573 rsa = PublicKeyToRSA(&key_block->data_key); |
384 if (!rsa) { | 574 if (!rsa) { |
385 error("Error parsing data key.\n"); | 575 error("Error parsing data key.\n"); |
386 return 1; | 576 return 1; |
387 } | 577 } |
388 | 578 |
389 /* Verify preamble */ | 579 /* Verify preamble */ |
390 preamble = (VbKernelPreambleHeader*)(blob + now); | 580 preamble = (VbKernelPreambleHeader*)(blob + now); |
391 if (0 != VerifyKernelPreamble2(preamble, blob_size - now, rsa)) { | 581 if (0 != VerifyKernelPreamble2(preamble, blob_size - now, rsa)) { |
392 error("Error verifying preamble.\n"); | 582 error("Error verifying preamble.\n"); |
393 return 1; | 583 return 1; |
394 } | 584 } |
395 now += preamble->preamble_size; | 585 now += preamble->preamble_size; |
396 | 586 |
397 printf("Preamble:\n"); | 587 printf("Preamble:\n"); |
398 printf(" Size: %" PRIu64 "\n", preamble->preamble_size); | 588 printf(" Size: 0x%" PRIx64 "\n", preamble->preamble_size); |
399 printf(" Header version: %" PRIu32 ".%" PRIu32"\n", | 589 printf(" Header version: %" PRIu32 ".%" PRIu32"\n", |
400 preamble->header_version_major, preamble->header_version_minor); | 590 preamble->header_version_major, preamble->header_version_minor); |
401 printf(" Kernel version: %" PRIu64 "\n", preamble->kernel_version); | 591 printf(" Kernel version: %" PRIu64 "\n", preamble->kernel_version); |
402 printf(" Body load address: 0x%" PRIx64 "\n", preamble->body_load_address); | 592 printf(" Body load address: 0x%" PRIx64 "\n", preamble->body_load_address); |
403 printf(" Body size: 0x%" PRIx64 "\n", | 593 printf(" Body size: 0x%" PRIx64 "\n", |
404 preamble->body_signature.data_size); | 594 preamble->body_signature.data_size); |
405 printf(" Bootloader address: 0x%" PRIx64 "\n", preamble->bootloader_address)
; | 595 printf(" Bootloader address: 0x%" PRIx64 "\n", preamble->bootloader_address)
; |
406 printf(" Bootloader size: 0x%" PRIx64 "\n", preamble->bootloader_size); | 596 printf(" Bootloader size: 0x%" PRIx64 "\n", preamble->bootloader_size); |
407 | 597 |
408 /* Verify body */ | 598 /* Verify body */ |
409 if (0 != VerifyData(blob + now, &preamble->body_signature, rsa)) { | 599 if (0 != VerifyData(blob + now, &preamble->body_signature, rsa)) { |
410 error("Error verifying kernel body.\n"); | 600 error("Error verifying kernel body.\n"); |
411 return 1; | 601 return 1; |
412 } | 602 } |
413 printf("Body verification succeeded.\n"); | 603 printf("Body verification succeeded.\n"); |
414 return 0; | 604 return 0; |
415 } | 605 } |
416 | 606 |
417 | 607 |
418 int main(int argc, char* argv[]) { | 608 int main(int argc, char* argv[]) { |
419 | |
420 char* filename = NULL; | 609 char* filename = NULL; |
| 610 char* oldfile = NULL; |
421 char* key_block_file = NULL; | 611 char* key_block_file = NULL; |
422 char* signpubkey = NULL; | 612 char* signpubkey = NULL; |
423 char* signprivate = NULL; | 613 char* signprivate = NULL; |
424 uint64_t version = 0; | 614 uint64_t version = 0; |
425 char* vmlinuz = NULL; | 615 char* vmlinuz = NULL; |
426 char* bootloader = NULL; | 616 char* bootloader = NULL; |
427 char* config_file = NULL; | 617 char* config_file = NULL; |
428 uint64_t pad = 65536; | 618 int vblockonly = 0; |
| 619 uint64_t pad = DEFAULT_PADDING; |
429 int mode = 0; | 620 int mode = 0; |
430 int parse_error = 0; | 621 int parse_error = 0; |
431 char* e; | 622 char* e; |
432 int i; | 623 int i,r; |
| 624 blob_t *bp; |
433 | 625 |
434 while ((i = getopt_long(argc, argv, "", long_opts, NULL)) != -1) { | 626 |
| 627 char *progname = strrchr(argv[0], '/'); |
| 628 if (progname) |
| 629 progname++; |
| 630 else |
| 631 progname = argv[0]; |
| 632 |
| 633 while ((i = getopt_long(argc, argv, ":", long_opts, NULL)) != -1) { |
435 switch (i) { | 634 switch (i) { |
436 case '?': | 635 case '?': |
437 /* Unhandled option */ | 636 /* Unhandled option */ |
438 printf("Unknown option\n"); | |
439 parse_error = 1; | 637 parse_error = 1; |
440 break; | 638 break; |
441 | 639 |
442 case OPT_MODE_PACK: | 640 case OPT_MODE_PACK: |
| 641 case OPT_MODE_REPACK: |
443 case OPT_MODE_VERIFY: | 642 case OPT_MODE_VERIFY: |
444 mode = i; | 643 mode = i; |
445 filename = optarg; | 644 filename = optarg; |
446 break; | 645 break; |
447 | 646 |
| 647 case OPT_OLDBLOB: |
| 648 oldfile = optarg; |
| 649 break; |
| 650 |
448 case OPT_KEYBLOCK: | 651 case OPT_KEYBLOCK: |
449 key_block_file = optarg; | 652 key_block_file = optarg; |
450 break; | 653 break; |
451 | 654 |
452 case OPT_SIGNPUBKEY: | 655 case OPT_SIGNPUBKEY: |
453 signpubkey = optarg; | 656 signpubkey = optarg; |
454 break; | 657 break; |
455 | 658 |
456 case OPT_SIGNPRIVATE: | 659 case OPT_SIGNPRIVATE: |
457 signprivate = optarg; | 660 signprivate = optarg; |
458 break; | 661 break; |
459 | 662 |
460 case OPT_VMLINUZ: | 663 case OPT_VMLINUZ: |
461 vmlinuz = optarg; | 664 vmlinuz = optarg; |
462 break; | 665 break; |
463 | 666 |
464 case OPT_BOOTLOADER: | 667 case OPT_BOOTLOADER: |
465 bootloader = optarg; | 668 bootloader = optarg; |
466 break; | 669 break; |
467 | 670 |
468 case OPT_CONFIG: | 671 case OPT_CONFIG: |
469 config_file = optarg; | 672 config_file = optarg; |
470 break; | 673 break; |
471 | 674 |
| 675 case OPT_VBLOCKONLY: |
| 676 vblockonly = 1; |
| 677 break; |
| 678 |
472 case OPT_VERSION: | 679 case OPT_VERSION: |
473 version = strtoul(optarg, &e, 0); | 680 version = strtoul(optarg, &e, 0); |
474 if (!*optarg || (e && *e)) { | 681 if (!*optarg || (e && *e)) { |
475 printf("Invalid --version\n"); | 682 fprintf(stderr, "Invalid --version\n"); |
476 parse_error = 1; | 683 parse_error = 1; |
477 } | 684 } |
478 break; | 685 break; |
479 | 686 |
480 case OPT_PAD: | 687 case OPT_PAD: |
481 pad = strtoul(optarg, &e, 0); | 688 pad = strtoul(optarg, &e, 0); |
482 if (!*optarg || (e && *e)) { | 689 if (!*optarg || (e && *e)) { |
483 printf("Invalid --pad\n"); | 690 fprintf(stderr, "Invalid --pad\n"); |
484 parse_error = 1; | 691 parse_error = 1; |
485 } | 692 } |
486 break; | 693 break; |
487 } | 694 } |
488 } | 695 } |
489 | 696 |
490 if (parse_error) | 697 if (parse_error) |
491 return PrintHelp(); | 698 return PrintHelp(progname); |
492 | 699 |
493 switch(mode) { | 700 switch(mode) { |
494 case OPT_MODE_PACK: | 701 case OPT_MODE_PACK: |
495 return Pack(filename, key_block_file, signprivate, version, vmlinuz, | 702 bp = NewBlob(version, vmlinuz, bootloader, config_file); |
496 bootloader, config_file, pad); | 703 if (!bp) |
| 704 return 1; |
| 705 r = Pack(filename, key_block_file, signprivate, bp, pad, vblockonly); |
| 706 FreeBlob(bp); |
| 707 return r; |
| 708 |
| 709 case OPT_MODE_REPACK: |
| 710 bp = OldBlob(oldfile); |
| 711 if (!bp) |
| 712 return 1; |
| 713 r = Pack(filename, key_block_file, signprivate, bp, pad, vblockonly); |
| 714 FreeBlob(bp); |
| 715 return r; |
| 716 |
497 case OPT_MODE_VERIFY: | 717 case OPT_MODE_VERIFY: |
498 return Verify(filename, signpubkey); | 718 return Verify(filename, signpubkey); |
| 719 |
499 default: | 720 default: |
500 printf("Must specify a mode.\n"); | 721 fprintf(stderr, |
501 return PrintHelp(); | 722 "You must specify a mode: --pack, --repack or --verify\n"); |
| 723 return PrintHelp(progname); |
502 } | 724 } |
503 } | 725 } |
OLD | NEW |