Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(356)

Unified Diff: utility/vbutil_kernel.c

Issue 2812034: Adding --repack and --headeronly options to vbutil_kernel (Closed) Base URL: ssh://git@chromiumos-git//vboot_reference.git
Patch Set: oops. Created 10 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « utility/vbutil_firmware.c ('k') | utility/vbutil_keyblock.c » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: utility/vbutil_kernel.c
diff --git a/utility/vbutil_kernel.c b/utility/vbutil_kernel.c
index 81b9e445d93478bb5926337cf88da4fe94ec8132..8b67051481d5f6f48fc31ca2157bb8cb84a2169f 100644
--- a/utility/vbutil_kernel.c
+++ b/utility/vbutil_kernel.c
@@ -5,12 +5,16 @@
* Verified boot kernel utility
*/
+#include <errno.h>
#include <getopt.h>
#include <inttypes.h> /* For PRIu64 */
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
#include <unistd.h>
#include "cryptolib.h"
@@ -22,11 +26,14 @@
/* Global opt */
static int opt_debug = 0;
+static const int DEFAULT_PADDING = 65536;
/* Command line options */
enum {
OPT_MODE_PACK = 1000,
+ OPT_MODE_REPACK,
OPT_MODE_VERIFY,
+ OPT_OLDBLOB,
OPT_KEYBLOCK,
OPT_SIGNPUBKEY,
OPT_SIGNPRIVATE,
@@ -34,12 +41,15 @@ enum {
OPT_VMLINUZ,
OPT_BOOTLOADER,
OPT_CONFIG,
+ OPT_VBLOCKONLY,
OPT_PAD,
};
static struct option long_opts[] = {
{"pack", 1, 0, OPT_MODE_PACK },
+ {"repack", 1, 0, OPT_MODE_REPACK },
{"verify", 1, 0, OPT_MODE_VERIFY },
+ {"oldblob", 1, 0, OPT_OLDBLOB },
{"keyblock", 1, 0, OPT_KEYBLOCK },
{"signpubkey", 1, 0, OPT_SIGNPUBKEY },
{"signprivate", 1, 0, OPT_SIGNPRIVATE },
@@ -47,6 +57,7 @@ static struct option long_opts[] = {
{"vmlinuz", 1, 0, OPT_VMLINUZ },
{"bootloader", 1, 0, OPT_BOOTLOADER },
{"config", 1, 0, OPT_CONFIG },
+ {"vblockonly", 0, 0, OPT_VBLOCKONLY },
{"pad", 1, 0, OPT_PAD },
{"debug", 0, &opt_debug, 1 },
{NULL, 0, 0, 0}
@@ -54,25 +65,46 @@ static struct option long_opts[] = {
/* Print help and return error */
-static int PrintHelp(void) {
-
- puts("vbutil_kernel - Verified boot key block utility\n"
- "\n"
- "Usage: vbutil_kernel <--pack|--verify> <file> [OPTIONS]\n"
- "\n"
- "For '--pack <file>', required OPTIONS are:\n"
- " --keyblock <file> Key block in .keyblock format\n"
- " --signprivate <file> Signing private key in .pem format\n"
- " --version <number> Kernel version\n"
- " --vmlinuz <file> Linux kernel image\n"
- " --bootloader <file> Bootloader stub\n"
- " --config <file> Config file\n"
- "Optional OPTIONS are:\n"
- " --pad <number> Padding size in bytes\n"
- "\n"
- "For '--verify <file>', required OPTIONS are:\n"
- " --signpubkey <file> Signing public key in .vbpubk format\n"
- "");
+static int PrintHelp(char *progname) {
+ fprintf(stderr,
+ "This program creates, signs, and verifies the kernel blob\n");
+ fprintf(stderr,
+ "\n"
+ "Usage: %s --pack <file> [PARAMETERS]\n"
+ "\n"
+ " Required parameters:\n"
+ " --keyblock <file> Key block in .keyblock format\n"
+ " --signprivate <file> Signing private key in .pem format\n"
+ " --version <number> Kernel version\n"
+ " --vmlinuz <file> Linux kernel bzImage file\n"
+ " --bootloader <file> Bootloader stub\n"
+ " --config <file> Config file\n"
+ "\n"
+ " Optional:\n"
+ " --pad <number> Verification padding size in bytes\n"
+ " --vblockonly Emit just the verification blob\n",
+ progname);
+ fprintf(stderr,
+ "\nOR\n\n"
+ "Usage: %s --repack <file> [PARAMETERS]\n"
+ "\n"
+ " Required parameters:\n"
+ " --keyblock <file> Key block in .keyblock format\n"
+ " --signprivate <file> Signing private key in .pem format\n"
+ " --oldblob <file> Previously packed kernel blob\n"
+ "\n"
+ " Optional:\n"
+ " --pad <number> Verification padding size in bytes\n"
+ " --vblockonly Emit just the verification blob\n",
+ progname);
+ fprintf(stderr,
+ "\nOR\n\n"
+ "Usage: %s --verify <file> [PARAMETERS]\n"
+ "\n"
+ " Required parameters:\n"
+ " --signpubkey <file> Signing public key in .vbpubk format\n"
+ "\n",
+ progname);
return 1;
}
@@ -121,76 +153,68 @@ static unsigned int find_cmdline_start(char *input, unsigned int max_len) {
}
-/* Pack a .kernel */
-static int Pack(const char* outfile, const char* keyblock_file,
- const char* signprivate, uint64_t version,
- const char* vmlinuz, const char* bootloader_file,
- const char* config_file, uint64_t pad) {
+typedef struct blob_s {
+ /* Stuff needed by VbKernelPreambleHeader */
+ uint64_t kernel_version;
+ uint64_t bootloader_address;
+ uint64_t bootloader_size;
+ /* Raw kernel blob data */
+ uint64_t blob_size;
+ uint8_t *blob;
+} blob_t;
+
+static void FreeBlob(blob_t *bp) {
+ if (bp) {
+ if (bp->blob)
+ Free(bp->blob);
+ Free(bp);
+ }
+}
+
+/* Create a blob from its components */
+static blob_t *NewBlob(uint64_t version,
+ const char* vmlinuz,
+ const char* bootloader_file,
+ const char* config_file) {
+ blob_t *bp;
struct linux_kernel_header *lh = 0;
struct linux_kernel_params *params = 0;
- VbPrivateKey* signing_key;
- VbSignature* body_sig;
- VbKernelPreambleHeader* preamble;
- VbKeyBlockHeader* key_block;
- uint64_t key_block_size;
uint8_t* config_buf;
uint64_t config_size;
uint8_t* bootloader_buf;
uint64_t bootloader_size;
- uint64_t bootloader_mem_start;
- uint64_t bootloader_mem_size;
uint8_t* kernel_buf;
uint64_t kernel_size;
uint64_t kernel32_start = 0;
uint64_t kernel32_size = 0;
uint32_t cmdline_addr;
uint8_t* blob = NULL;
- uint64_t blob_size;
uint64_t now = 0;
- FILE* f;
uint64_t i;
- if (!outfile) {
- error("Must specify output filename\n");
- return 1;
- }
- if (!keyblock_file || !signprivate) {
- error("Must specify all keys\n");
- return 1;
- }
if (!vmlinuz || !bootloader_file || !config_file) {
error("Must specify all input files\n");
- return 1;
+ return 0;
}
- /* Read the key block and private key */
- key_block = (VbKeyBlockHeader*)ReadFile(keyblock_file, &key_block_size);
- if (!key_block) {
- error("Error reading key block.\n");
- return 1;
- }
- if (pad < key_block->key_block_size) {
- error("Pad too small\n");
- return 1;
- }
-
- signing_key = PrivateKeyRead(signprivate, key_block->data_key.algorithm);
- if (!signing_key) {
- error("Error reading signing key.\n");
- return 1;
+ bp = (blob_t *)Malloc(sizeof(blob_t));
+ if (!bp) {
+ error("Couldn't allocate bytes for blob_t.\n");
+ return 0;
}
+ bp->kernel_version = version;
/* Read the config file */
Debug("Reading %s\n", config_file);
config_buf = ReadFile(config_file, &config_size);
if (!config_buf)
- return 1;
+ return 0;
Debug(" config file size=0x%" PRIx64 "\n", config_size);
if (CROS_CONFIG_SIZE <= config_size) { /* need room for trailing '\0' */
error("Config file %s is too large (>= %d bytes)\n",
config_file, CROS_CONFIG_SIZE);
- return 1;
+ return 0;
}
/* Replace newlines with spaces */
for (i = 0; i < config_size; i++)
@@ -201,18 +225,18 @@ static int Pack(const char* outfile, const char* keyblock_file,
Debug("Reading %s\n", bootloader_file);
bootloader_buf = ReadFile(bootloader_file, &bootloader_size);
if (!bootloader_buf)
- return 1;
+ return 0;
Debug(" bootloader file size=0x%" PRIx64 "\n", bootloader_size);
/* Read the kernel */
Debug("Reading %s\n", vmlinuz);
kernel_buf = ReadFile(vmlinuz, &kernel_size);
if (!kernel_buf)
- return 1;
+ return 0;
Debug(" kernel file size=0x%" PRIx64 "\n", kernel_size);
if (!kernel_size) {
error("Empty kernel file\n");
- return 1;
+ return 0;
}
/* The first part of vmlinuz is a header, followed by a real-mode
@@ -221,24 +245,25 @@ static int Pack(const char* outfile, const char* keyblock_file,
kernel32_start = (lh->setup_sects + 1) << 9;
if (kernel32_start >= kernel_size) {
error("Malformed kernel\n");
- return 1;
+ return 0;
}
kernel32_size = kernel_size - kernel32_start;
Debug(" kernel32_start=0x%" PRIx64 "\n", kernel32_start);
Debug(" kernel32_size=0x%" PRIx64 "\n", kernel32_size);
/* Allocate and zero the blob we need. */
- blob_size = roundup(kernel32_size, CROS_ALIGN) +
+ bp->blob_size = roundup(kernel32_size, CROS_ALIGN) +
CROS_CONFIG_SIZE +
CROS_PARAMS_SIZE +
roundup(bootloader_size, CROS_ALIGN);
- blob = (uint8_t *)Malloc(blob_size);
- Debug("blob_size=0x%" PRIx64 "\n", blob_size);
+ blob = (uint8_t *)Malloc(bp->blob_size);
+ Debug("blob_size=0x%" PRIx64 "\n", bp->blob_size);
if (!blob) {
- error("Couldn't allocate %ld bytes.\n", blob_size);
- return 1;
+ error("Couldn't allocate %ld bytes.\n", bp->blob_size);
+ return 0;
}
- Memset(blob, 0, blob_size);
+ Memset(blob, 0, bp->blob_size);
+ bp->blob = blob;
/* Copy the 32-bit kernel. */
Debug("kernel goes at blob+=0x%" PRIx64 "\n", now);
@@ -273,13 +298,13 @@ static int Pack(const char* outfile, const char* keyblock_file,
/* Finally, append the bootloader. Remember where it will load in
* memory, too. */
Debug("bootloader goes at blob+=0x%" PRIx64 "\n", now);
- bootloader_mem_start = CROS_32BIT_ENTRY_ADDR + now;
- bootloader_mem_size = roundup(bootloader_size, CROS_ALIGN);
- Debug(" bootloader_mem_start=0x%" PRIx64 "\n", bootloader_mem_start);
- Debug(" bootloader_mem_size=0x%" PRIx64 "\n", bootloader_mem_size);
+ bp->bootloader_address = CROS_32BIT_ENTRY_ADDR + now;
+ bp->bootloader_size = roundup(bootloader_size, CROS_ALIGN);
+ Debug(" bootloader_address=0x%" PRIx64 "\n", bp->bootloader_address);
+ Debug(" bootloader_size=0x%" PRIx64 "\n", bp->bootloader_size);
if (bootloader_size)
Memcpy(blob + now, bootloader_buf, bootloader_size);
- now += bootloader_mem_size;
+ now += bp->bootloader_size;
Debug("end of blob is 0x%" PRIx64 "\n", now);
/* Free input buffers */
@@ -287,18 +312,172 @@ static int Pack(const char* outfile, const char* keyblock_file,
Free(config_buf);
Free(bootloader_buf);
+ /* Success */
+ return bp;
+}
+
+
+/* Pull the blob_t stuff out of a prepacked kernel blob file */
+static blob_t *OldBlob(const char* filename) {
+ FILE* fp;
+ blob_t *bp;
+ struct stat statbuf;
+ VbKeyBlockHeader* key_block;
+ VbKernelPreambleHeader* preamble;
+ uint64_t now = 0;
+ uint8_t buf[DEFAULT_PADDING];
+
+ if (!filename) {
+ error("Must specify prepacked blob to read\n");
+ return 0;
+ }
+
+ if (0 != stat(filename, &statbuf)) {
+ error("unable to stat %s: %s\n", filename, strerror(errno));
+ return 0;
+ }
+
+ Debug("%s size is 0x%" PRIx64 "\n", filename, statbuf.st_size);
+ if (statbuf.st_size < DEFAULT_PADDING) {
+ error("%s is too small to be a valid kernel blob\n");
+ return 0;
+ }
+
+ Debug("Reading %s\n", filename);
+ fp = fopen(filename, "rb");
+ if (!fp) {
+ error("Unable to open file %s: %s\n", filename, strerror(errno));
+ return 0;
+ }
+
+ if (1 != fread(buf, sizeof(buf), 1, fp)) {
+ error("Unable to read header from %s: %s\n", filename, strerror(errno));
+ fclose(fp);
+ return 0;
+ }
+
+ /* Skip the key block */
+ key_block = (VbKeyBlockHeader*)buf;
+ Debug("Keyblock is 0x%" PRIx64 " bytes\n", key_block->key_block_size);
+ now += key_block->key_block_size;
+ if (now > statbuf.st_size) {
+ error("key_block_size advances past the end of the blob\n");
+ return 0;
+ }
+
+ /* Skip the preamble */
+ preamble = (VbKernelPreambleHeader*)(buf + now);
+ Debug("Preamble is 0x%" PRIx64 " bytes\n", preamble->preamble_size);
+ now += preamble->preamble_size;
+ if (now > statbuf.st_size) {
+ error("preamble_size advances past the end of the blob\n");
+ return 0;
+ }
+
+ /* Go find the kernel blob */
+ Debug("kernel blob is at offset 0x%" PRIx64 "\n", now);
+ if (0 != fseek(fp, now, SEEK_SET)) {
+ error("Unable to seek to 0x%" PRIx64 " in %s: %s\n", now, filename,
+ strerror(errno));
+ fclose(fp);
+ return 0;
+ }
+
+ /* Remember what we've got */
+ bp = (blob_t *)Malloc(sizeof(blob_t));
+ if (!bp) {
+ error("Couldn't allocate bytes for blob_t.\n");
+ fclose(fp);
+ return 0;
+ }
+
+ bp->kernel_version = preamble->kernel_version;
+ bp->bootloader_address = preamble->bootloader_address;
+ bp->bootloader_size = preamble->bootloader_size;
+ bp->blob_size = preamble->body_signature.data_size;
+
+ Debug(" kernel_version = %d\n", bp->kernel_version);
+ Debug(" bootloader_address = 0x%" PRIx64 "\n", bp->bootloader_address);
+ Debug(" bootloader_size = 0x%" PRIx64 "\n", bp->bootloader_size);
+ Debug(" blob_size = 0x%" PRIx64 "\n", bp->blob_size);
+
+ bp->blob = (uint8_t *)Malloc(bp->blob_size);
+ if (!bp->blob) {
+ error("Couldn't allocate 0x%" PRIx64 " bytes for blob_t.\n", bp->blob_size);
+ fclose(fp);
+ Free(bp);
+ return 0;
+ }
+
+ /* read it in */
+ if (1 != fread(bp->blob, bp->blob_size, 1, fp)) {
+ error("Unable to read kernel blob from %s: %s\n", filename, strerror(errno));
+ fclose(fp);
+ Free(bp);
+ return 0;
+ }
+
+ /* done */
+ fclose(fp);
+
+ return bp;
+}
+
+
+/* Pack a .kernel */
+static int Pack(const char* outfile, const char* keyblock_file,
+ const char* signprivate, blob_t *bp, uint64_t pad,
+ int vblockonly) {
+ VbPrivateKey* signing_key;
+ VbSignature* body_sig;
+ VbKernelPreambleHeader* preamble;
+ VbKeyBlockHeader* key_block;
+ uint64_t key_block_size;
+ FILE* f;
+ uint64_t i;
+
+ if (!outfile) {
+ error("Must specify output filename\n");
+ return 1;
+ }
+ if (!keyblock_file || !signprivate) {
+ error("Must specify all keys\n");
+ return 1;
+ }
+ if (!bp) {
+ error("Refusing to pack invalid kernel blob\n");
+ return 1;
+ }
+
+ /* Read the key block and private key */
+ key_block = (VbKeyBlockHeader*)ReadFile(keyblock_file, &key_block_size);
+ if (!key_block) {
+ error("Error reading key block.\n");
+ return 1;
+ }
+ if (pad < key_block->key_block_size) {
+ error("Pad too small\n");
+ return 1;
+ }
+
+ signing_key = PrivateKeyReadPem(signprivate, key_block->data_key.algorithm);
+ if (!signing_key) {
+ error("Error reading signing key.\n");
+ return 1;
+ }
+
/* Sign the kernel data */
- body_sig = CalculateSignature(blob, blob_size, signing_key);
+ body_sig = CalculateSignature(bp->blob, bp->blob_size, signing_key);
if (!body_sig) {
error("Error calculating body signature\n");
return 1;
}
/* Create preamble */
- preamble = CreateKernelPreamble(version,
+ preamble = CreateKernelPreamble(bp->kernel_version,
CROS_32BIT_ENTRY_ADDR,
- bootloader_mem_start,
- bootloader_mem_size,
+ bp->bootloader_address,
+ bp->bootloader_size,
body_sig,
pad - key_block_size,
signing_key);
@@ -316,17 +495,28 @@ static int Pack(const char* outfile, const char* keyblock_file,
}
Debug("0x%" PRIx64 " bytes of key_block\n", key_block_size);
Debug("0x%" PRIx64 " bytes of preamble\n", preamble->preamble_size);
- Debug("0x%" PRIx64 " bytes of blob\n", blob_size);
i = ((1 != fwrite(key_block, key_block_size, 1, f)) ||
- (1 != fwrite(preamble, preamble->preamble_size, 1, f)) ||
- (1 != fwrite(blob, blob_size, 1, f)));
- fclose(f);
+ (1 != fwrite(preamble, preamble->preamble_size, 1, f)));
if (i) {
error("Can't write output file %s\n", outfile);
+ fclose(f);
unlink(outfile);
return 1;
}
+ if (!vblockonly) {
+ Debug("0x%" PRIx64 " bytes of blob\n", bp->blob_size);
+ i = (1 != fwrite(bp->blob, bp->blob_size, 1, f));
+ if (i) {
+ error("Can't write output file %s\n", outfile);
+ fclose(f);
+ unlink(outfile);
+ return 1;
+ }
+ }
+
+ fclose(f);
+
/* Success */
return 0;
}
@@ -373,7 +563,7 @@ static int Verify(const char* infile, const char* signpubkey) {
printf("Key block:\n");
data_key = &key_block->data_key;
- printf(" Size: %" PRIu64 "\n", key_block->key_block_size);
+ printf(" Size: 0x%" PRIx64 "\n", key_block->key_block_size);
printf(" Data key algorithm: %" PRIu64 " %s\n", data_key->algorithm,
(data_key->algorithm < kNumAlgorithms ?
algo_strings[data_key->algorithm] : "(invalid)"));
@@ -395,7 +585,7 @@ static int Verify(const char* infile, const char* signpubkey) {
now += preamble->preamble_size;
printf("Preamble:\n");
- printf(" Size: %" PRIu64 "\n", preamble->preamble_size);
+ printf(" Size: 0x%" PRIx64 "\n", preamble->preamble_size);
printf(" Header version: %" PRIu32 ".%" PRIu32"\n",
preamble->header_version_major, preamble->header_version_minor);
printf(" Kernel version: %" PRIu64 "\n", preamble->kernel_version);
@@ -416,8 +606,8 @@ static int Verify(const char* infile, const char* signpubkey) {
int main(int argc, char* argv[]) {
-
char* filename = NULL;
+ char* oldfile = NULL;
char* key_block_file = NULL;
char* signpubkey = NULL;
char* signprivate = NULL;
@@ -425,26 +615,39 @@ int main(int argc, char* argv[]) {
char* vmlinuz = NULL;
char* bootloader = NULL;
char* config_file = NULL;
- uint64_t pad = 65536;
+ int vblockonly = 0;
+ uint64_t pad = DEFAULT_PADDING;
int mode = 0;
int parse_error = 0;
char* e;
- int i;
+ int i,r;
+ blob_t *bp;
- while ((i = getopt_long(argc, argv, "", long_opts, NULL)) != -1) {
+
+ char *progname = strrchr(argv[0], '/');
+ if (progname)
+ progname++;
+ else
+ progname = argv[0];
+
+ while ((i = getopt_long(argc, argv, ":", long_opts, NULL)) != -1) {
switch (i) {
case '?':
/* Unhandled option */
- printf("Unknown option\n");
parse_error = 1;
break;
case OPT_MODE_PACK:
+ case OPT_MODE_REPACK:
case OPT_MODE_VERIFY:
mode = i;
filename = optarg;
break;
+ case OPT_OLDBLOB:
+ oldfile = optarg;
+ break;
+
case OPT_KEYBLOCK:
key_block_file = optarg;
break;
@@ -469,10 +672,14 @@ int main(int argc, char* argv[]) {
config_file = optarg;
break;
+ case OPT_VBLOCKONLY:
+ vblockonly = 1;
+ break;
+
case OPT_VERSION:
version = strtoul(optarg, &e, 0);
if (!*optarg || (e && *e)) {
- printf("Invalid --version\n");
+ fprintf(stderr, "Invalid --version\n");
parse_error = 1;
}
break;
@@ -480,7 +687,7 @@ int main(int argc, char* argv[]) {
case OPT_PAD:
pad = strtoul(optarg, &e, 0);
if (!*optarg || (e && *e)) {
- printf("Invalid --pad\n");
+ fprintf(stderr, "Invalid --pad\n");
parse_error = 1;
}
break;
@@ -488,16 +695,31 @@ int main(int argc, char* argv[]) {
}
if (parse_error)
- return PrintHelp();
+ return PrintHelp(progname);
switch(mode) {
case OPT_MODE_PACK:
- return Pack(filename, key_block_file, signprivate, version, vmlinuz,
- bootloader, config_file, pad);
+ bp = NewBlob(version, vmlinuz, bootloader, config_file);
+ if (!bp)
+ return 1;
+ r = Pack(filename, key_block_file, signprivate, bp, pad, vblockonly);
+ FreeBlob(bp);
+ return r;
+
+ case OPT_MODE_REPACK:
+ bp = OldBlob(oldfile);
+ if (!bp)
+ return 1;
+ r = Pack(filename, key_block_file, signprivate, bp, pad, vblockonly);
+ FreeBlob(bp);
+ return r;
+
case OPT_MODE_VERIFY:
return Verify(filename, signpubkey);
+
default:
- printf("Must specify a mode.\n");
- return PrintHelp();
+ fprintf(stderr,
+ "You must specify a mode: --pack, --repack or --verify\n");
+ return PrintHelp(progname);
}
}
« no previous file with comments | « utility/vbutil_firmware.c ('k') | utility/vbutil_keyblock.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698