| 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 <getopt.h> | 8 #include <getopt.h> |
| 9 #include <inttypes.h> /* For PRIu64 */ | 9 #include <inttypes.h> /* For PRIu64 */ |
| 10 #include <stdarg.h> |
| 10 #include <stddef.h> | 11 #include <stddef.h> |
| 11 #include <stdio.h> | 12 #include <stdio.h> |
| 12 #include <stdlib.h> | 13 #include <stdlib.h> |
| 13 #include <unistd.h> | 14 #include <unistd.h> |
| 14 | 15 |
| 15 #include "cryptolib.h" | 16 #include "cryptolib.h" |
| 16 #include "host_common.h" | 17 #include "host_common.h" |
| 17 #include "kernel_blob.h" | 18 #include "kernel_blob.h" |
| 18 #include "vboot_common.h" | 19 #include "vboot_common.h" |
| 19 | 20 |
| 20 | 21 |
| 22 /* Global opt */ |
| 23 static int opt_debug = 0; |
| 24 |
| 25 |
| 21 /* Command line options */ | 26 /* Command line options */ |
| 22 enum { | 27 enum { |
| 23 OPT_MODE_PACK = 1000, | 28 OPT_MODE_PACK = 1000, |
| 24 OPT_MODE_VERIFY, | 29 OPT_MODE_VERIFY, |
| 25 OPT_KEYBLOCK, | 30 OPT_KEYBLOCK, |
| 26 OPT_SIGNPUBKEY, | 31 OPT_SIGNPUBKEY, |
| 27 OPT_SIGNPRIVATE, | 32 OPT_SIGNPRIVATE, |
| 28 OPT_VERSION, | 33 OPT_VERSION, |
| 29 OPT_VMLINUZ, | 34 OPT_VMLINUZ, |
| 30 OPT_BOOTLOADER, | 35 OPT_BOOTLOADER, |
| 31 OPT_CONFIG, | 36 OPT_CONFIG, |
| 32 OPT_PAD, | 37 OPT_PAD, |
| 33 }; | 38 }; |
| 34 | 39 |
| 35 static struct option long_opts[] = { | 40 static struct option long_opts[] = { |
| 36 {"pack", 1, 0, OPT_MODE_PACK }, | 41 {"pack", 1, 0, OPT_MODE_PACK }, |
| 37 {"verify", 1, 0, OPT_MODE_VERIFY }, | 42 {"verify", 1, 0, OPT_MODE_VERIFY }, |
| 38 {"keyblock", 1, 0, OPT_KEYBLOCK }, | 43 {"keyblock", 1, 0, OPT_KEYBLOCK }, |
| 39 {"signpubkey", 1, 0, OPT_SIGNPUBKEY }, | 44 {"signpubkey", 1, 0, OPT_SIGNPUBKEY }, |
| 40 {"signprivate", 1, 0, OPT_SIGNPRIVATE }, | 45 {"signprivate", 1, 0, OPT_SIGNPRIVATE }, |
| 41 {"version", 1, 0, OPT_VERSION }, | 46 {"version", 1, 0, OPT_VERSION }, |
| 42 {"vmlinuz", 1, 0, OPT_VMLINUZ }, | 47 {"vmlinuz", 1, 0, OPT_VMLINUZ }, |
| 43 {"bootloader", 1, 0, OPT_BOOTLOADER }, | 48 {"bootloader", 1, 0, OPT_BOOTLOADER }, |
| 44 {"config", 1, 0, OPT_CONFIG }, | 49 {"config", 1, 0, OPT_CONFIG }, |
| 45 {"pad", 1, 0, OPT_PAD }, | 50 {"pad", 1, 0, OPT_PAD }, |
| 51 {"debug", 0, &opt_debug, 1 }, |
| 46 {NULL, 0, 0, 0} | 52 {NULL, 0, 0, 0} |
| 47 }; | 53 }; |
| 48 | 54 |
| 49 | 55 |
| 50 /* Print help and return error */ | 56 /* Print help and return error */ |
| 51 static int PrintHelp(void) { | 57 static int PrintHelp(void) { |
| 52 | 58 |
| 53 puts("vbutil_kernel - Verified boot key block utility\n" | 59 puts("vbutil_kernel - Verified boot key block utility\n" |
| 54 "\n" | 60 "\n" |
| 55 "Usage: vbutil_kernel <--pack|--verify> <file> [OPTIONS]\n" | 61 "Usage: vbutil_kernel <--pack|--verify> <file> [OPTIONS]\n" |
| 56 "\n" | 62 "\n" |
| 57 "For '--pack <file>', required OPTIONS are:\n" | 63 "For '--pack <file>', required OPTIONS are:\n" |
| 58 " --keyblock <file> Key block in .keyblock format\n" | 64 " --keyblock <file> Key block in .keyblock format\n" |
| 59 " --signprivate <file> Signing private key in .pem format\n" | 65 " --signprivate <file> Signing private key in .pem format\n" |
| 60 " --version <number> Kernel version\n" | 66 " --version <number> Kernel version\n" |
| 61 " --vmlinuz <file> Linux kernel image\n" | 67 " --vmlinuz <file> Linux kernel image\n" |
| 62 " --bootloader <file> Bootloader stub\n" | 68 " --bootloader <file> Bootloader stub\n" |
| 63 " --config <file> Config file\n" | 69 " --config <file> Config file\n" |
| 64 "Optional OPTIONS are:\n" | 70 "Optional OPTIONS are:\n" |
| 65 " --pad <number> Padding size in bytes\n" | 71 " --pad <number> Padding size in bytes\n" |
| 66 "\n" | 72 "\n" |
| 67 "For '--verify <file>', required OPTIONS are:\n" | 73 "For '--verify <file>', required OPTIONS are:\n" |
| 68 " --signpubkey <file> Signing public key in .vbpubk format\n" | 74 " --signpubkey <file> Signing public key in .vbpubk format\n" |
| 69 ""); | 75 ""); |
| 70 return 1; | 76 return 1; |
| 71 } | 77 } |
| 72 | 78 |
| 79 static void Debug(const char *format, ...) { |
| 80 if (!opt_debug) |
| 81 return; |
| 82 |
| 83 va_list ap; |
| 84 va_start(ap, format); |
| 85 fprintf(stderr, "DEBUG: "); |
| 86 vfprintf(stderr, format, ap); |
| 87 va_end(ap); |
| 88 } |
| 89 |
| 73 | 90 |
| 74 /* Return the smallest integral multiple of [alignment] that is equal | 91 /* Return the smallest integral multiple of [alignment] that is equal |
| 75 * to or greater than [val]. Used to determine the number of | 92 * to or greater than [val]. Used to determine the number of |
| 76 * pages/sectors/blocks/whatever needed to contain [val] | 93 * pages/sectors/blocks/whatever needed to contain [val] |
| 77 * items/bytes/etc. */ | 94 * items/bytes/etc. */ |
| 78 static uint64_t roundup(uint64_t val, uint64_t alignment) { | 95 static uint64_t roundup(uint64_t val, uint64_t alignment) { |
| 79 uint64_t rem = val % alignment; | 96 uint64_t rem = val % alignment; |
| 80 if ( rem ) | 97 if ( rem ) |
| 81 return val + (alignment - rem); | 98 return val + (alignment - rem); |
| 82 return val; | 99 return val; |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 158 return 1; | 175 return 1; |
| 159 } | 176 } |
| 160 | 177 |
| 161 signing_key = PrivateKeyRead(signprivate, key_block->data_key.algorithm); | 178 signing_key = PrivateKeyRead(signprivate, key_block->data_key.algorithm); |
| 162 if (!signing_key) { | 179 if (!signing_key) { |
| 163 error("Error reading signing key.\n"); | 180 error("Error reading signing key.\n"); |
| 164 return 1; | 181 return 1; |
| 165 } | 182 } |
| 166 | 183 |
| 167 /* Read the config file */ | 184 /* Read the config file */ |
| 185 Debug("Reading %s\n", config_file); |
| 168 config_buf = ReadFile(config_file, &config_size); | 186 config_buf = ReadFile(config_file, &config_size); |
| 169 if (!config_buf) | 187 if (!config_buf) |
| 170 return 1; | 188 return 1; |
| 189 Debug(" config file size=0x%" PRIx64 "\n", config_size); |
| 171 if (CROS_CONFIG_SIZE <= config_size) { /* need room for trailing '\0' */ | 190 if (CROS_CONFIG_SIZE <= config_size) { /* need room for trailing '\0' */ |
| 172 error("Config file %s is too large (>= %d bytes)\n", | 191 error("Config file %s is too large (>= %d bytes)\n", |
| 173 config_file, CROS_CONFIG_SIZE); | 192 config_file, CROS_CONFIG_SIZE); |
| 174 return 1; | 193 return 1; |
| 175 } | 194 } |
| 176 /* Replace newlines with spaces */ | 195 /* Replace newlines with spaces */ |
| 177 for (i = 0; i < config_size; i++) | 196 for (i = 0; i < config_size; i++) |
| 178 if ('\n' == config_buf[i]) | 197 if ('\n' == config_buf[i]) |
| 179 config_buf[i] = ' '; | 198 config_buf[i] = ' '; |
| 180 | 199 |
| 181 /* Read the bootloader */ | 200 /* Read the bootloader */ |
| 201 Debug("Reading %s\n", bootloader_file); |
| 182 bootloader_buf = ReadFile(bootloader_file, &bootloader_size); | 202 bootloader_buf = ReadFile(bootloader_file, &bootloader_size); |
| 183 if (!bootloader_buf) | 203 if (!bootloader_buf) |
| 184 return 1; | 204 return 1; |
| 205 Debug(" bootloader file size=0x%" PRIx64 "\n", bootloader_size); |
| 185 | 206 |
| 186 /* Read the kernel */ | 207 /* Read the kernel */ |
| 208 Debug("Reading %s\n", vmlinuz); |
| 187 kernel_buf = ReadFile(vmlinuz, &kernel_size); | 209 kernel_buf = ReadFile(vmlinuz, &kernel_size); |
| 188 if (!kernel_buf) | 210 if (!kernel_buf) |
| 189 return 1; | 211 return 1; |
| 212 Debug(" kernel file size=0x%" PRIx64 "\n", kernel_size); |
| 190 if (!kernel_size) { | 213 if (!kernel_size) { |
| 191 error("Empty kernel file\n"); | 214 error("Empty kernel file\n"); |
| 192 return 1; | 215 return 1; |
| 193 } | 216 } |
| 194 | 217 |
| 195 /* The first part of vmlinuz is a header, followed by a real-mode | 218 /* The first part of vmlinuz is a header, followed by a real-mode |
| 196 * boot stub. We only want the 32-bit part. */ | 219 * boot stub. We only want the 32-bit part. */ |
| 197 lh = (struct linux_kernel_header *)kernel_buf; | 220 lh = (struct linux_kernel_header *)kernel_buf; |
| 198 kernel32_start = (lh->setup_sects + 1) << 9; | 221 kernel32_start = (lh->setup_sects + 1) << 9; |
| 199 if (kernel32_start >= kernel_size) { | 222 if (kernel32_start >= kernel_size) { |
| 200 error("Malformed kernel\n"); | 223 error("Malformed kernel\n"); |
| 201 return 1; | 224 return 1; |
| 202 } | 225 } |
| 203 kernel32_size = kernel_size - kernel32_start; | 226 kernel32_size = kernel_size - kernel32_start; |
| 227 Debug(" kernel32_start=0x%" PRIx64 "\n", kernel32_start); |
| 228 Debug(" kernel32_size=0x%" PRIx64 "\n", kernel32_size); |
| 204 | 229 |
| 205 /* Allocate and zero the blob we need. */ | 230 /* Allocate and zero the blob we need. */ |
| 206 blob_size = roundup(kernel32_size, CROS_ALIGN) + | 231 blob_size = roundup(kernel32_size, CROS_ALIGN) + |
| 207 CROS_CONFIG_SIZE + | 232 CROS_CONFIG_SIZE + |
| 208 CROS_PARAMS_SIZE + | 233 CROS_PARAMS_SIZE + |
| 209 roundup(bootloader_size, CROS_ALIGN); | 234 roundup(bootloader_size, CROS_ALIGN); |
| 210 blob = (uint8_t *)Malloc(blob_size); | 235 blob = (uint8_t *)Malloc(blob_size); |
| 236 Debug("blob_size=0x%" PRIx64 "\n", blob_size); |
| 211 if (!blob) { | 237 if (!blob) { |
| 212 error("Couldn't allocate %ld bytes.\n", blob_size); | 238 error("Couldn't allocate %ld bytes.\n", blob_size); |
| 213 return 1; | 239 return 1; |
| 214 } | 240 } |
| 215 Memset(blob, 0, blob_size); | 241 Memset(blob, 0, blob_size); |
| 216 | 242 |
| 217 /* Copy the 32-bit kernel. */ | 243 /* Copy the 32-bit kernel. */ |
| 244 Debug("kernel goes at blob+=0x%" PRIx64 "\n", now); |
| 218 if (kernel32_size) | 245 if (kernel32_size) |
| 219 Memcpy(blob + now, kernel_buf + kernel32_start, kernel32_size); | 246 Memcpy(blob + now, kernel_buf + kernel32_start, kernel32_size); |
| 220 now += roundup(now + kernel32_size, CROS_ALIGN); | 247 now += roundup(now + kernel32_size, CROS_ALIGN); |
| 221 | 248 |
| 249 Debug("config goes at blob+0x%" PRIx64 "\n", now); |
| 222 /* Find the load address of the commandline. We'll need it later. */ | 250 /* Find the load address of the commandline. We'll need it later. */ |
| 223 cmdline_addr = CROS_32BIT_ENTRY_ADDR + now + | 251 cmdline_addr = CROS_32BIT_ENTRY_ADDR + now + |
| 224 find_cmdline_start((char *)config_buf, config_size); | 252 find_cmdline_start((char *)config_buf, config_size); |
| 253 Debug(" cmdline_addr=0x%" PRIx64 "\n", cmdline_addr); |
| 225 | 254 |
| 226 /* Copy the config. */ | 255 /* Copy the config. */ |
| 227 if (config_size) | 256 if (config_size) |
| 228 Memcpy(blob + now, config_buf, config_size); | 257 Memcpy(blob + now, config_buf, config_size); |
| 229 now += CROS_CONFIG_SIZE; | 258 now += CROS_CONFIG_SIZE; |
| 230 | 259 |
| 231 /* The zeropage data is next. Overlay the linux_kernel_header onto it, and | 260 /* The zeropage data is next. Overlay the linux_kernel_header onto it, and |
| 232 * tweak a few fields. */ | 261 * tweak a few fields. */ |
| 262 Debug("params goes at blob+=0x%" PRIx64 "\n", now); |
| 233 params = (struct linux_kernel_params *)(blob + now); | 263 params = (struct linux_kernel_params *)(blob + now); |
| 234 Memcpy(&(params->setup_sects), &(lh->setup_sects), | 264 Memcpy(&(params->setup_sects), &(lh->setup_sects), |
| 235 sizeof(*lh) - offsetof(struct linux_kernel_header, setup_sects)); | 265 sizeof(*lh) - offsetof(struct linux_kernel_header, setup_sects)); |
| 236 params->boot_flag = 0; | 266 params->boot_flag = 0; |
| 237 params->ramdisk_image = 0; /* we don't support initrd */ | 267 params->ramdisk_image = 0; /* we don't support initrd */ |
| 238 params->ramdisk_size = 0; | 268 params->ramdisk_size = 0; |
| 239 params->type_of_loader = 0xff; | 269 params->type_of_loader = 0xff; |
| 240 params->cmd_line_ptr = cmdline_addr; | 270 params->cmd_line_ptr = cmdline_addr; |
| 241 now += CROS_PARAMS_SIZE; | 271 now += CROS_PARAMS_SIZE; |
| 242 | 272 |
| 243 /* Finally, append the bootloader. Remember where it will load in | 273 /* Finally, append the bootloader. Remember where it will load in |
| 244 * memory, too. */ | 274 * memory, too. */ |
| 275 Debug("bootloader goes at blob+=0x%" PRIx64 "\n", now); |
| 245 bootloader_mem_start = CROS_32BIT_ENTRY_ADDR + now; | 276 bootloader_mem_start = CROS_32BIT_ENTRY_ADDR + now; |
| 246 bootloader_mem_size = roundup(bootloader_size, CROS_ALIGN); | 277 bootloader_mem_size = roundup(bootloader_size, CROS_ALIGN); |
| 278 Debug(" bootloader_mem_start=0x%" PRIx64 "\n", bootloader_mem_start); |
| 279 Debug(" bootloader_mem_size=0x%" PRIx64 "\n", bootloader_mem_size); |
| 247 if (bootloader_size) | 280 if (bootloader_size) |
| 248 Memcpy(blob + now, bootloader_buf, bootloader_size); | 281 Memcpy(blob + now, bootloader_buf, bootloader_size); |
| 249 now += bootloader_mem_size; | 282 now += bootloader_mem_size; |
| 283 Debug("end of blob is 0x%" PRIx64 "\n", now); |
| 250 | 284 |
| 251 /* Free input buffers */ | 285 /* Free input buffers */ |
| 252 Free(kernel_buf); | 286 Free(kernel_buf); |
| 253 Free(config_buf); | 287 Free(config_buf); |
| 254 Free(bootloader_buf); | 288 Free(bootloader_buf); |
| 255 | 289 |
| 256 /* Sign the kernel data */ | 290 /* Sign the kernel data */ |
| 257 body_sig = CalculateSignature(blob, blob_size, signing_key); | 291 body_sig = CalculateSignature(blob, blob_size, signing_key); |
| 258 if (!body_sig) { | 292 if (!body_sig) { |
| 259 error("Error calculating body signature\n"); | 293 error("Error calculating body signature\n"); |
| 260 return 1; | 294 return 1; |
| 261 } | 295 } |
| 262 | 296 |
| 263 /* Create preamble */ | 297 /* Create preamble */ |
| 264 preamble = CreateKernelPreamble(version, | 298 preamble = CreateKernelPreamble(version, |
| 265 CROS_32BIT_ENTRY_ADDR, | 299 CROS_32BIT_ENTRY_ADDR, |
| 266 bootloader_mem_start, | 300 bootloader_mem_start, |
| 267 bootloader_mem_size, | 301 bootloader_mem_size, |
| 268 body_sig, | 302 body_sig, |
| 269 pad - key_block_size, | 303 pad - key_block_size, |
| 270 signing_key); | 304 signing_key); |
| 271 if (!preamble) { | 305 if (!preamble) { |
| 272 error("Error creating preamble.\n"); | 306 error("Error creating preamble.\n"); |
| 273 return 1; | 307 return 1; |
| 274 } | 308 } |
| 275 | 309 |
| 276 /* Write the output file */ | 310 /* Write the output file */ |
| 311 Debug("writing %s...\n", outfile); |
| 277 f = fopen(outfile, "wb"); | 312 f = fopen(outfile, "wb"); |
| 278 if (!f) { | 313 if (!f) { |
| 279 error("Can't open output file %s\n", outfile); | 314 error("Can't open output file %s\n", outfile); |
| 280 return 1; | 315 return 1; |
| 281 } | 316 } |
| 317 Debug("0x%" PRIx64 " bytes of key_block\n", key_block_size); |
| 318 Debug("0x%" PRIx64 " bytes of preamble\n", preamble->preamble_size); |
| 319 Debug("0x%" PRIx64 " bytes of blob\n", blob_size); |
| 282 i = ((1 != fwrite(key_block, key_block_size, 1, f)) || | 320 i = ((1 != fwrite(key_block, key_block_size, 1, f)) || |
| 283 (1 != fwrite(preamble, preamble->preamble_size, 1, f)) || | 321 (1 != fwrite(preamble, preamble->preamble_size, 1, f)) || |
| 284 (1 != fwrite(blob, blob_size, 1, f))); | 322 (1 != fwrite(blob, blob_size, 1, f))); |
| 285 fclose(f); | 323 fclose(f); |
| 286 if (i) { | 324 if (i) { |
| 287 error("Can't write output file %s\n", outfile); | 325 error("Can't write output file %s\n", outfile); |
| 288 unlink(outfile); | 326 unlink(outfile); |
| 289 return 1; | 327 return 1; |
| 290 } | 328 } |
| 291 | 329 |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 354 error("Error verifying preamble.\n"); | 392 error("Error verifying preamble.\n"); |
| 355 return 1; | 393 return 1; |
| 356 } | 394 } |
| 357 now += preamble->preamble_size; | 395 now += preamble->preamble_size; |
| 358 | 396 |
| 359 printf("Preamble:\n"); | 397 printf("Preamble:\n"); |
| 360 printf(" Size: %" PRIu64 "\n", preamble->preamble_size); | 398 printf(" Size: %" PRIu64 "\n", preamble->preamble_size); |
| 361 printf(" Header version: %" PRIu32 ".%" PRIu32"\n", | 399 printf(" Header version: %" PRIu32 ".%" PRIu32"\n", |
| 362 preamble->header_version_major, preamble->header_version_minor); | 400 preamble->header_version_major, preamble->header_version_minor); |
| 363 printf(" Kernel version: %" PRIu64 "\n", preamble->kernel_version); | 401 printf(" Kernel version: %" PRIu64 "\n", preamble->kernel_version); |
| 364 printf(" Body load address: %" PRIu64 "\n", preamble->body_load_address); | 402 printf(" Body load address: 0x%" PRIx64 "\n", preamble->body_load_address); |
| 365 printf(" Body size: %" PRIu64 "\n", | 403 printf(" Body size: 0x%" PRIx64 "\n", |
| 366 preamble->body_signature.data_size); | 404 preamble->body_signature.data_size); |
| 367 printf(" Bootloader address: %" PRIu64 "\n", preamble->bootloader_address); | 405 printf(" Bootloader address: 0x%" PRIx64 "\n", preamble->bootloader_address)
; |
| 368 printf(" Bootloader size: %" PRIu64 "\n", preamble->bootloader_size); | 406 printf(" Bootloader size: 0x%" PRIx64 "\n", preamble->bootloader_size); |
| 369 | 407 |
| 370 /* Verify body */ | 408 /* Verify body */ |
| 371 if (0 != VerifyData(blob + now, &preamble->body_signature, rsa)) { | 409 if (0 != VerifyData(blob + now, &preamble->body_signature, rsa)) { |
| 372 error("Error verifying kernel body.\n"); | 410 error("Error verifying kernel body.\n"); |
| 373 return 1; | 411 return 1; |
| 374 } | 412 } |
| 375 printf("Body verification succeeded.\n"); | 413 printf("Body verification succeeded.\n"); |
| 376 return 0; | 414 return 0; |
| 377 } | 415 } |
| 378 | 416 |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 456 case OPT_MODE_PACK: | 494 case OPT_MODE_PACK: |
| 457 return Pack(filename, key_block_file, signprivate, version, vmlinuz, | 495 return Pack(filename, key_block_file, signprivate, version, vmlinuz, |
| 458 bootloader, config_file, pad); | 496 bootloader, config_file, pad); |
| 459 case OPT_MODE_VERIFY: | 497 case OPT_MODE_VERIFY: |
| 460 return Verify(filename, signpubkey); | 498 return Verify(filename, signpubkey); |
| 461 default: | 499 default: |
| 462 printf("Must specify a mode.\n"); | 500 printf("Must specify a mode.\n"); |
| 463 return PrintHelp(); | 501 return PrintHelp(); |
| 464 } | 502 } |
| 465 } | 503 } |
| OLD | NEW |