futility: Reformat to use kernel coding style

This just reformats the futility sources to conform to the Linux kernel
coding style. No functional changes.

BUG=chromium:224734
BRANCH=ToT
TEST=make runtests

Change-Id: I82df07dd3f8be2ad2f3df24cebe00a9a378b13f4
Signed-off-by: Bill Richardson <wfrichar@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/213915
Reviewed-by: Randall Spangler <rspangler@chromium.org>
This commit is contained in:
Bill Richardson
2014-08-24 22:07:17 -07:00
committed by chrome-internal-fetch
parent 8f15d74fd6
commit 31d95c2386
12 changed files with 3098 additions and 2997 deletions

View File

@@ -7,7 +7,7 @@
#include <errno.h> #include <errno.h>
#include <getopt.h> #include <getopt.h>
#include <inttypes.h> /* For PRIu64 */ #include <inttypes.h> /* For PRIu64 */
#include <stdarg.h> #include <stdarg.h>
#include <stddef.h> #include <stddef.h>
#include <stdio.h> #include <stdio.h>
@@ -23,336 +23,351 @@
#include "kernel_blob.h" #include "kernel_blob.h"
#include "vboot_common.h" #include "vboot_common.h"
/* Global opt */ /* Global opt */
static int opt_debug = 0; static int opt_debug = 0;
/* Command line options */ /* Command line options */
enum { enum {
OPT_MODE_SIGN = 1000, OPT_MODE_SIGN = 1000,
OPT_MODE_VERIFY, OPT_MODE_VERIFY,
OPT_KEYBLOCK, OPT_KEYBLOCK,
OPT_SIGNPRIVATE, OPT_SIGNPRIVATE,
OPT_VBLOCK, OPT_VBLOCK,
}; };
static const struct option long_opts[] = { static const struct option long_opts[] = {
{"sign", 1, 0, OPT_MODE_SIGN }, {"sign", 1, 0, OPT_MODE_SIGN},
{"verify", 1, 0, OPT_MODE_VERIFY }, {"verify", 1, 0, OPT_MODE_VERIFY},
{"keyblock", 1, 0, OPT_KEYBLOCK }, {"keyblock", 1, 0, OPT_KEYBLOCK},
{"signprivate", 1, 0, OPT_SIGNPRIVATE }, {"signprivate", 1, 0, OPT_SIGNPRIVATE},
{"vblock", 1, 0, OPT_VBLOCK }, {"vblock", 1, 0, OPT_VBLOCK},
{"debug", 0, &opt_debug, 1 }, {"debug", 0, &opt_debug, 1},
{NULL, 0, 0, 0} {NULL, 0, 0, 0}
}; };
/* Print help and return error */ /* Print help and return error */
static int PrintHelp(const char *progname) { static int PrintHelp(const char *progname)
fprintf(stderr, {
"This program is used to sign and verify developer-mode files\n"); fprintf(stderr,
fprintf(stderr, "This is used to sign and verify developer-mode files\n");
"\n" fprintf(stderr,
"Usage: %s --sign <file> [PARAMETERS]\n" "\n"
"\n" "Usage: %s --sign <file> [PARAMETERS]\n"
" Required parameters:\n" "\n"
" --keyblock <file> Key block in .keyblock format\n" " Required parameters:\n"
" --signprivate <file>" " --keyblock <file> Key block in .keyblock format\n"
" Private key to sign file data, in .vbprivk format\n" " --signprivate <file>"
" --vblock <file> Output signature in .vblock format\n" " Private key to sign file data, in .vbprivk format\n"
"\n", " --vblock <file>"
progname); " Output signature in .vblock format\n"
fprintf(stderr, "\n", progname);
"OR\n\n" fprintf(stderr,
"Usage: %s --verify <file> [PARAMETERS]\n" "OR\n\n"
"\n" "Usage: %s --verify <file> [PARAMETERS]\n"
" Required parameters:\n" "\n"
" --vblock <file> Signature file in .vblock format\n" " Required parameters:\n"
"\n" " --vblock <file>"
" Optional parameters:\n" " Signature file in .vblock format\n"
" --keyblock <file>" "\n"
" Extract .keyblock to file if verification succeeds\n" " Optional parameters:\n"
"\n", " --keyblock <file>"
progname); " Extract .keyblock to file if verification succeeds\n"
return 1; "\n", progname);
return 1;
} }
static void Debug(const char *format, ...) { static void Debug(const char *format, ...)
if (!opt_debug) {
return; if (!opt_debug)
return;
va_list ap; va_list ap;
va_start(ap, format); va_start(ap, format);
fprintf(stderr, "DEBUG: "); fprintf(stderr, "DEBUG: ");
vfprintf(stderr, format, ap); vfprintf(stderr, format, ap);
va_end(ap); va_end(ap);
} }
/* Sign a file. We'll reuse the same structs used to sign kernels, to avoid /* Sign a file. We'll reuse the same structs used to sign kernels, to avoid
having to declare yet another one for just this purpose. */ having to declare yet another one for just this purpose. */
static int Sign(const char* filename, const char* keyblock_file, static int Sign(const char *filename, const char *keyblock_file,
const char* signprivate_file, const char* outfile) { const char *signprivate_file, const char *outfile)
uint8_t* file_data; {
uint64_t file_size; uint8_t *file_data;
VbKeyBlockHeader* key_block; uint64_t file_size;
uint64_t key_block_size; VbKeyBlockHeader *key_block;
VbPrivateKey* signing_key; uint64_t key_block_size;
VbSignature* body_sig; VbPrivateKey *signing_key;
VbKernelPreambleHeader* preamble; VbSignature *body_sig;
FILE* output_fp; VbKernelPreambleHeader *preamble;
FILE *output_fp;
/* Read the file that we're going to sign. */ /* Read the file that we're going to sign. */
file_data = ReadFile(filename, &file_size); file_data = ReadFile(filename, &file_size);
if (!file_data) { if (!file_data) {
VbExError("Error reading file to sign.\n"); VbExError("Error reading file to sign.\n");
return 1; return 1;
} }
/* Get the key block and read the private key corresponding to it. */ /* Get the key block and read the private key corresponding to it. */
key_block = (VbKeyBlockHeader*)ReadFile(keyblock_file, &key_block_size); key_block =
if (!key_block) { (VbKeyBlockHeader *) ReadFile(keyblock_file, &key_block_size);
VbExError("Error reading key block.\n"); if (!key_block) {
return 1; VbExError("Error reading key block.\n");
} return 1;
signing_key = PrivateKeyRead(signprivate_file); }
if (!signing_key) { signing_key = PrivateKeyRead(signprivate_file);
VbExError("Error reading signing key.\n"); if (!signing_key) {
return 1; VbExError("Error reading signing key.\n");
} return 1;
}
/* Sign the file data */ /* Sign the file data */
body_sig = CalculateSignature(file_data, file_size, signing_key); body_sig = CalculateSignature(file_data, file_size, signing_key);
if (!body_sig) { if (!body_sig) {
VbExError("Error calculating body signature\n"); VbExError("Error calculating body signature\n");
return 1; return 1;
} }
/* Create preamble */ /* Create preamble */
preamble = CreateKernelPreamble((uint64_t)0, preamble = CreateKernelPreamble((uint64_t) 0,
(uint64_t)0, (uint64_t) 0,
(uint64_t)0, (uint64_t) 0,
(uint64_t)0, (uint64_t) 0,
body_sig, body_sig, (uint64_t) 0, signing_key);
(uint64_t)0, if (!preamble) {
signing_key); VbExError("Error creating preamble.\n");
if (!preamble) { return 1;
VbExError("Error creating preamble.\n"); }
return 1;
}
/* Write the output file */ /* Write the output file */
Debug("writing %s...\n", outfile); Debug("writing %s...\n", outfile);
output_fp = fopen(outfile, "wb"); output_fp = fopen(outfile, "wb");
if (!output_fp) { if (!output_fp) {
VbExError("Can't open output file %s\n", outfile); VbExError("Can't open output file %s\n", outfile);
return 1; return 1;
} }
Debug("0x%" PRIx64 " bytes of key_block\n", key_block_size); 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 preamble\n", preamble->preamble_size);
if ((1 != fwrite(key_block, key_block_size, 1, output_fp)) || if ((1 != fwrite(key_block, key_block_size, 1, output_fp)) ||
(1 != fwrite(preamble, preamble->preamble_size, 1, output_fp))) { (1 != fwrite(preamble, preamble->preamble_size, 1, output_fp))) {
VbExError("Can't write output file %s\n", outfile); VbExError("Can't write output file %s\n", outfile);
fclose(output_fp); fclose(output_fp);
unlink(outfile); unlink(outfile);
return 1; return 1;
} }
fclose(output_fp); fclose(output_fp);
/* Done */ /* Done */
free(preamble); free(preamble);
free(body_sig); free(body_sig);
free(signing_key); free(signing_key);
free(key_block); free(key_block);
free(file_data); free(file_data);
/* Success */ /* Success */
return 0; return 0;
} }
static int Verify(const char* filename, const char* vblock_file, static int Verify(const char *filename, const char *vblock_file,
const char* keyblock_file) { const char *keyblock_file)
uint8_t* file_data; {
uint64_t file_size; uint8_t *file_data;
uint8_t* buf; uint64_t file_size;
uint64_t buf_size; uint8_t *buf;
VbKeyBlockHeader* key_block; uint64_t buf_size;
VbKernelPreambleHeader* preamble; VbKeyBlockHeader *key_block;
VbPublicKey* data_key; VbKernelPreambleHeader *preamble;
RSAPublicKey* rsa; VbPublicKey *data_key;
uint64_t current_buf_offset = 0; RSAPublicKey *rsa;
uint64_t current_buf_offset = 0;
/* Read the file that we're going to verify. */ /* Read the file that we're going to verify. */
file_data = ReadFile(filename, &file_size); file_data = ReadFile(filename, &file_size);
if (!file_data) { if (!file_data) {
VbExError("Error reading file to sign.\n"); VbExError("Error reading file to sign.\n");
return 1; return 1;
} }
/* Read the vblock that we're going to use on it */ /* Read the vblock that we're going to use on it */
buf = ReadFile(vblock_file, &buf_size); buf = ReadFile(vblock_file, &buf_size);
if (!buf) { if (!buf) {
VbExError("Error reading vblock_file.\n"); VbExError("Error reading vblock_file.\n");
return 1; return 1;
} }
/* Find the key block */ /* Find the key block */
key_block = (VbKeyBlockHeader*)buf; key_block = (VbKeyBlockHeader *) buf;
Debug("Keyblock is 0x%" PRIx64 " bytes\n", key_block->key_block_size); Debug("Keyblock is 0x%" PRIx64 " bytes\n", key_block->key_block_size);
current_buf_offset += key_block->key_block_size; current_buf_offset += key_block->key_block_size;
if (current_buf_offset > buf_size) { if (current_buf_offset > buf_size) {
VbExError("key_block_size advances past the end of the buffer\n"); VbExError
return 1; ("key_block_size advances past the end of the buffer\n");
} return 1;
}
/* Find the preamble */ /* Find the preamble */
preamble = (VbKernelPreambleHeader*)(buf + current_buf_offset); preamble = (VbKernelPreambleHeader *) (buf + current_buf_offset);
Debug("Preamble is 0x%" PRIx64 " bytes\n", preamble->preamble_size); Debug("Preamble is 0x%" PRIx64 " bytes\n", preamble->preamble_size);
current_buf_offset += preamble->preamble_size; current_buf_offset += preamble->preamble_size;
if (current_buf_offset > buf_size ) { if (current_buf_offset > buf_size) {
VbExError("preamble_size advances past the end of the buffer\n"); VbExError
return 1; ("preamble_size advances past the end of the buffer\n");
} return 1;
}
Debug("Current buf offset is at 0x%" PRIx64 " bytes\n", current_buf_offset); Debug("Current buf offset is at 0x%" PRIx64 " bytes\n",
current_buf_offset);
/* Check the key block (hash only) */ /* Check the key block (hash only) */
if (0 != KeyBlockVerify(key_block, key_block->key_block_size, NULL, 1)) { if (0 != KeyBlockVerify(key_block, key_block->key_block_size,
VbExError("Error verifying key block.\n"); NULL, 1)) {
return 1; VbExError("Error verifying key block.\n");
} return 1;
}
printf("Key block:\n"); printf("Key block:\n");
data_key = &key_block->data_key; data_key = &key_block->data_key;
printf(" Size: 0x%" PRIx64 "\n", key_block->key_block_size); printf(" Size: 0x%" PRIx64 "\n",
printf(" Data key algorithm: %" PRIu64 " %s\n", data_key->algorithm, key_block->key_block_size);
(data_key->algorithm < kNumAlgorithms ? printf(" Data key algorithm: %" PRIu64 " %s\n", data_key->algorithm,
algo_strings[data_key->algorithm] : "(invalid)")); (data_key->algorithm <
printf(" Data key version: %" PRIu64 "\n", data_key->key_version); kNumAlgorithms ? algo_strings[data_key->
printf(" Flags: %" PRIu64 "\n", key_block->key_block_flags); algorithm] : "(invalid)"));
printf(" Data key version: %" PRIu64 "\n", data_key->key_version);
printf(" Flags: %" PRIu64 "\n",
key_block->key_block_flags);
/* Verify preamble */
rsa = PublicKeyToRSA(&key_block->data_key);
if (!rsa) {
VbExError("Error parsing data key.\n");
return 1;
}
if (0 != VerifyKernelPreamble(preamble, preamble->preamble_size, rsa)) {
VbExError("Error verifying preamble.\n");
return 1;
}
/* Verify preamble */ printf("Preamble:\n");
rsa = PublicKeyToRSA(&key_block->data_key); printf(" Size: 0x%" PRIx64 "\n",
if (!rsa) { preamble->preamble_size);
VbExError("Error parsing data key.\n"); printf(" Header version: %" PRIu32 ".%" PRIu32 "\n",
return 1; preamble->header_version_major, preamble->header_version_minor);
} printf(" Kernel version: %" PRIu64 "\n",
if (0 != VerifyKernelPreamble(preamble, preamble->preamble_size, rsa)) { preamble->kernel_version);
VbExError("Error verifying preamble.\n"); printf(" Body load address: 0x%" PRIx64 "\n",
return 1; preamble->body_load_address);
} printf(" Body size: 0x%" PRIx64 "\n",
preamble->body_signature.data_size);
printf(" Bootloader address: 0x%" PRIx64 "\n",
preamble->bootloader_address);
printf(" Bootloader size: 0x%" PRIx64 "\n",
preamble->bootloader_size);
printf("Preamble:\n"); /* Verify body */
printf(" Size: 0x%" PRIx64 "\n", preamble->preamble_size); if (0 !=
printf(" Header version: %" PRIu32 ".%" PRIu32"\n", VerifyData(file_data, file_size, &preamble->body_signature, rsa)) {
preamble->header_version_major, preamble->header_version_minor); VbExError("Error verifying kernel body.\n");
printf(" Kernel version: %" PRIu64 "\n", preamble->kernel_version); return 1;
printf(" Body load address: 0x%" PRIx64 "\n", preamble->body_load_address); }
printf(" Body size: 0x%" PRIx64 "\n", printf("Body verification succeeded.\n");
preamble->body_signature.data_size);
printf(" Bootloader address: 0x%" PRIx64 "\n",
preamble->bootloader_address);
printf(" Bootloader size: 0x%" PRIx64 "\n", preamble->bootloader_size);
/* Verify body */ if (keyblock_file) {
if (0 != VerifyData(file_data, file_size, &preamble->body_signature, rsa)) { if (0 !=
VbExError("Error verifying kernel body.\n"); WriteFile(keyblock_file, key_block,
return 1; key_block->key_block_size)) {
} VbExError("Unable to export keyblock file\n");
printf("Body verification succeeded.\n"); return 1;
}
printf("Key block exported to %s\n", keyblock_file);
}
if (keyblock_file) { return 0;
if (0 != WriteFile(keyblock_file, key_block, key_block->key_block_size)) {
VbExError("Unable to export keyblock file\n");
return 1;
}
printf("Key block exported to %s\n", keyblock_file);
}
return 0;
} }
static int do_dev_sign_file(int argc, char *argv[])
{
char *filename = NULL;
char *keyblock_file = NULL;
char *signprivate_file = NULL;
char *vblock_file = NULL;
int mode = 0;
int parse_error = 0;
int option_index;
static int do_dev_sign_file(int argc, char* argv[]) { char *progname = strrchr(argv[0], '/');
char* filename = NULL; if (progname)
char* keyblock_file = NULL; progname++;
char* signprivate_file = NULL; else
char* vblock_file = NULL; progname = argv[0];
int mode = 0;
int parse_error = 0;
int option_index;
char *progname = strrchr(argv[0], '/'); while ((option_index =
if (progname) getopt_long(argc, argv, ":", long_opts, NULL)) != -1
progname++; && !parse_error) {
else switch (option_index) {
progname = argv[0]; default:
case '?':
/* Unhandled option */
parse_error = 1;
break;
while ((option_index = getopt_long(argc, argv, ":", long_opts, NULL)) != -1 && case 0:
!parse_error) { /* silently handled option */
switch (option_index) { break;
default:
case '?':
/* Unhandled option */
parse_error = 1;
break;
case 0: case OPT_MODE_SIGN:
/* silently handled option */ case OPT_MODE_VERIFY:
break; if (mode && (mode != option_index)) {
fprintf(stderr,
"Only one mode can be specified\n");
parse_error = 1;
break;
}
mode = option_index;
filename = optarg;
break;
case OPT_MODE_SIGN: case OPT_KEYBLOCK:
case OPT_MODE_VERIFY: keyblock_file = optarg;
if (mode && (mode != option_index)) { break;
fprintf(stderr, "Only a single mode can be specified\n");
parse_error = 1;
break;
}
mode = option_index;
filename = optarg;
break;
case OPT_KEYBLOCK: case OPT_SIGNPRIVATE:
keyblock_file = optarg; signprivate_file = optarg;
break; break;
case OPT_SIGNPRIVATE: case OPT_VBLOCK:
signprivate_file = optarg; vblock_file = optarg;
break; break;
}
}
case OPT_VBLOCK: if (parse_error)
vblock_file = optarg; return PrintHelp(progname);
break;
}
}
if (parse_error) switch (mode) {
return PrintHelp(progname); case OPT_MODE_SIGN:
if (!keyblock_file || !signprivate_file || !vblock_file) {
fprintf(stderr, "Some required options are missing\n");
return PrintHelp(progname);
}
return Sign(filename, keyblock_file, signprivate_file,
vblock_file);
switch(mode) { case OPT_MODE_VERIFY:
case OPT_MODE_SIGN: if (!vblock_file) {
if (!keyblock_file || !signprivate_file || !vblock_file) { fprintf(stderr, "Some required options are missing\n");
fprintf(stderr, "Some required options are missing\n"); return PrintHelp(progname);
return PrintHelp(progname); }
} return Verify(filename, vblock_file, keyblock_file);
return Sign(filename, keyblock_file, signprivate_file, vblock_file);
case OPT_MODE_VERIFY: default:
if (!vblock_file) { fprintf(stderr, "You must specify either --sign or --verify\n");
fprintf(stderr, "Some required options are missing\n"); return PrintHelp(progname);
return PrintHelp(progname); }
}
return Verify(filename, vblock_file, keyblock_file);
default: /* NOTREACHED */
fprintf(stderr, return 1;
"You must specify either --sign or --verify\n");
return PrintHelp(progname);
}
/* NOTREACHED */
return 1;
} }
DECLARE_FUTIL_COMMAND(dev_sign_file, do_dev_sign_file, DECLARE_FUTIL_COMMAND(dev_sign_file, do_dev_sign_file,

View File

@@ -29,452 +29,459 @@ static void *base_of_rom;
static size_t size_of_rom; static size_t size_of_rom;
static int opt_gaps = 0; static int opt_gaps = 0;
/* Return 0 if successful */ /* Return 0 if successful */
static int dump_fmap(const void *ptr, int argc, char *argv[]) static int dump_fmap(const void *ptr, int argc, char *argv[])
{ {
int i, retval = 0; int i, retval = 0;
char buf[80]; // DWR: magic number char buf[80]; /* DWR: magic number */
const FmapHeader *fmh = (const FmapHeader*)ptr; const FmapHeader *fmh = (const FmapHeader *)ptr;
const FmapAreaHeader *ah = (const FmapAreaHeader*)(ptr + sizeof(FmapHeader)); const FmapAreaHeader *ah =
(const FmapAreaHeader *)(ptr + sizeof(FmapHeader));
if (FMT_NORMAL == opt_format) { if (FMT_NORMAL == opt_format) {
snprintf(buf, FMAP_SIGNATURE_SIZE+1, "%s", fmh->fmap_signature); snprintf(buf, FMAP_SIGNATURE_SIZE + 1, "%s",
printf("fmap_signature %s\n", buf); fmh->fmap_signature);
printf("fmap_version: %d.%d\n", printf("fmap_signature %s\n", buf);
fmh->fmap_ver_major, fmh->fmap_ver_minor); printf("fmap_version: %d.%d\n",
printf("fmap_base: 0x%" PRIx64 "\n", fmh->fmap_base); fmh->fmap_ver_major, fmh->fmap_ver_minor);
printf("fmap_size: 0x%08x (%d)\n", fmh->fmap_size, fmh->fmap_size); printf("fmap_base: 0x%" PRIx64 "\n", fmh->fmap_base);
snprintf(buf, FMAP_NAMELEN+1, "%s", fmh->fmap_name); printf("fmap_size: 0x%08x (%d)\n", fmh->fmap_size,
printf("fmap_name: %s\n", buf); fmh->fmap_size);
printf("fmap_nareas: %d\n", fmh->fmap_nareas); snprintf(buf, FMAP_NAMELEN + 1, "%s", fmh->fmap_name);
} printf("fmap_name: %s\n", buf);
printf("fmap_nareas: %d\n", fmh->fmap_nareas);
}
for (i = 0; i < fmh->fmap_nareas; i++, ah++) { for (i = 0; i < fmh->fmap_nareas; i++, ah++) {
snprintf(buf, FMAP_NAMELEN+1, "%s", ah->area_name); snprintf(buf, FMAP_NAMELEN + 1, "%s", ah->area_name);
if (argc) { if (argc) {
int j, found=0; int j, found = 0;
for (j = 0; j < argc; j++) for (j = 0; j < argc; j++)
if (!strcmp(argv[j], buf)) { if (!strcmp(argv[j], buf)) {
found = 1; found = 1;
break; break;
} }
if (!found) { if (!found) {
continue; continue;
} }
} }
switch (opt_format) { switch (opt_format) {
case FMT_PRETTY: case FMT_PRETTY:
printf("%s %d %d\n", buf, ah->area_offset, ah->area_size); printf("%s %d %d\n", buf, ah->area_offset,
break; ah->area_size);
case FMT_FLASHROM: break;
if (ah->area_size) case FMT_FLASHROM:
printf("0x%08x:0x%08x %s\n", ah->area_offset, if (ah->area_size)
ah->area_offset + ah->area_size - 1, buf); printf("0x%08x:0x%08x %s\n", ah->area_offset,
break; ah->area_offset + ah->area_size - 1,
default: buf);
printf("area: %d\n", i+1); break;
printf("area_offset: 0x%08x\n", ah->area_offset); default:
printf("area_size: 0x%08x (%d)\n", ah->area_size, ah->area_size); printf("area: %d\n", i + 1);
printf("area_name: %s\n", buf); printf("area_offset: 0x%08x\n", ah->area_offset);
} printf("area_size: 0x%08x (%d)\n", ah->area_size,
ah->area_size);
printf("area_name: %s\n", buf);
}
if (opt_extract) { if (opt_extract) {
char *s; char *s;
for (s = buf; *s; s++) for (s = buf; *s; s++)
if (*s == ' ') if (*s == ' ')
*s = '_'; *s = '_';
FILE *fp = fopen(buf,"wb"); FILE *fp = fopen(buf, "wb");
if (!fp) { if (!fp) {
fprintf(stderr, "%s: can't open %s: %s\n", fprintf(stderr, "%s: can't open %s: %s\n",
progname, buf, strerror(errno)); progname, buf, strerror(errno));
retval = 1; retval = 1;
} else if (!ah->area_size) { } else if (!ah->area_size) {
fprintf(stderr, "%s: section %s has zero size\n", progname, buf); fprintf(stderr,
} else if (ah->area_offset + ah->area_size > size_of_rom) { "%s: section %s has zero size\n",
fprintf(stderr, "%s: section %s is larger than the image\n", progname, buf);
progname, buf); } else if (ah->area_offset + ah->area_size >
retval = 1; size_of_rom) {
} else if (1 != fwrite(base_of_rom + ah->area_offset, fprintf(stderr, "%s: section %s is larger"
ah->area_size, 1, fp)) { " than the image\n", progname, buf);
fprintf(stderr, "%s: can't write %s: %s\n", retval = 1;
progname, buf, strerror(errno)); } else if (1 != fwrite(base_of_rom + ah->area_offset,
retval = 1; ah->area_size, 1, fp)) {
} else { fprintf(stderr, "%s: can't write %s: %s\n",
if (FMT_NORMAL == opt_format) progname, buf, strerror(errno));
printf("saved as \"%s\"\n", buf); retval = 1;
} } else {
fclose(fp); if (FMT_NORMAL == opt_format)
} printf("saved as \"%s\"\n", buf);
} }
fclose(fp);
}
}
return retval; return retval;
} }
/****************************************************************************/ /****************************************************************************/
/* Stuff for human-readable form */ /* Stuff for human-readable form */
typedef struct dup_s { typedef struct dup_s {
char *name; char *name;
struct dup_s *next; struct dup_s *next;
} dupe_t; } dupe_t;
typedef struct node_s { typedef struct node_s {
char *name; char *name;
uint32_t start; uint32_t start;
uint32_t size; uint32_t size;
uint32_t end; uint32_t end;
struct node_s *parent; struct node_s *parent;
int num_children; int num_children;
struct node_s **child; struct node_s **child;
dupe_t *alias; dupe_t *alias;
} node_t; } node_t;
static node_t *all_nodes; static node_t *all_nodes;
static void sort_nodes(int num, node_t *ary[]) static void sort_nodes(int num, node_t * ary[])
{ {
int i, j; int i, j;
node_t *tmp; node_t *tmp;
/* bubble-sort is quick enough with only a few entries */ /* bubble-sort is quick enough with only a few entries */
for (i = 0; i < num; i++) { for (i = 0; i < num; i++) {
for (j = i + 1; j < num; j++) { for (j = i + 1; j < num; j++) {
if (ary[j]->start > ary[i]->start) { if (ary[j]->start > ary[i]->start) {
tmp = ary[i]; tmp = ary[i];
ary[i] = ary[j]; ary[i] = ary[j];
ary[j] = tmp; ary[j] = tmp;
} }
} }
} }
} }
static void line(int indent, char *name, static void line(int indent, char *name,
uint32_t start, uint32_t end, uint32_t size, char *append) uint32_t start, uint32_t end, uint32_t size, char *append)
{ {
int i; int i;
for (i = 0; i < indent; i++) for (i = 0; i < indent; i++)
printf(" "); printf(" ");
printf("%-25s %08x %08x %08x%s\n", name, start, end, size, printf("%-25s %08x %08x %08x%s\n", name, start, end, size,
append ? append : ""); append ? append : "");
} }
static int gapcount; static int gapcount;
static void empty(int indent, uint32_t start, uint32_t end, char *name) static void empty(int indent, uint32_t start, uint32_t end, char *name)
{ {
char buf[80]; char buf[80];
if (opt_gaps) { if (opt_gaps) {
sprintf(buf, " // gap in %s", name); sprintf(buf, " // gap in %s", name);
line(indent + 1, "", start, end, end - start, buf); line(indent + 1, "", start, end, end - start, buf);
} }
gapcount++; gapcount++;
} }
static void show(node_t *p, int indent, int show_first) static void show(node_t * p, int indent, int show_first)
{ {
int i; int i;
dupe_t *alias; dupe_t *alias;
if (show_first) { if (show_first) {
line(indent, p->name, p->start, p->end, p->size, 0); line(indent, p->name, p->start, p->end, p->size, 0);
for (alias = p->alias; alias; alias = alias->next) for (alias = p->alias; alias; alias = alias->next)
line(indent, alias->name, p->start, p->end, p->size, " // DUPLICATE"); line(indent, alias->name, p->start, p->end, p->size,
} " // DUPLICATE");
sort_nodes(p->num_children, p->child); }
for (i = 0; i < p->num_children; i++) { sort_nodes(p->num_children, p->child);
if (i == 0 && p->end != p->child[i]->end) for (i = 0; i < p->num_children; i++) {
empty(indent, p->child[i]->end, p->end, p->name); if (i == 0 && p->end != p->child[i]->end)
show(p->child[i], indent + show_first, 1); empty(indent, p->child[i]->end, p->end, p->name);
if (i < p->num_children - 1 && p->child[i]->start != p->child[i+1]->end) show(p->child[i], indent + show_first, 1);
empty(indent, p->child[i+1]->end, p->child[i]->start, p->name); if (i < p->num_children - 1
if (i == p->num_children - 1 && p->child[i]->start != p->start) && p->child[i]->start != p->child[i + 1]->end)
empty(indent, p->start, p->child[i]->start, p->name); empty(indent, p->child[i + 1]->end, p->child[i]->start,
} p->name);
if (i == p->num_children - 1 && p->child[i]->start != p->start)
empty(indent, p->start, p->child[i]->start, p->name);
}
} }
static int overlaps(int i, int j) static int overlaps(int i, int j)
{ {
node_t *a = all_nodes + i; node_t *a = all_nodes + i;
node_t *b = all_nodes + j; node_t *b = all_nodes + j;
return ((a->start < b->start) && (b->start < a->end) && return ((a->start < b->start) && (b->start < a->end) &&
(b->start < a->end) && (a->end < b->end)); (b->start < a->end) && (a->end < b->end));
} }
static int encloses(int i, int j) static int encloses(int i, int j)
{ {
node_t *a = all_nodes + i; node_t *a = all_nodes + i;
node_t *b = all_nodes + j; node_t *b = all_nodes + j;
return ((a->start <= b->start) && return ((a->start <= b->start) && (a->end >= b->end));
(a->end >= b->end));
} }
static int duplicates(int i, int j) static int duplicates(int i, int j)
{ {
node_t *a = all_nodes + i; node_t *a = all_nodes + i;
node_t *b = all_nodes + j; node_t *b = all_nodes + j;
return ((a->start == b->start) && return ((a->start == b->start) && (a->end == b->end));
(a->end == b->end));
} }
static void add_dupe(int i, int j, int numnodes) static void add_dupe(int i, int j, int numnodes)
{ {
int k; int k;
dupe_t *alias; dupe_t *alias;
alias = (dupe_t *)malloc(sizeof(dupe_t)); alias = (dupe_t *) malloc(sizeof(dupe_t));
alias->name = all_nodes[j].name; alias->name = all_nodes[j].name;
alias->next = all_nodes[i].alias; alias->next = all_nodes[i].alias;
all_nodes[i].alias = alias; all_nodes[i].alias = alias;
for (k = j; k < numnodes; k++ ) for (k = j; k < numnodes; k++)
all_nodes[k] = all_nodes[k + 1]; all_nodes[k] = all_nodes[k + 1];
} }
static void add_child(node_t *p, int n) static void add_child(node_t * p, int n)
{ {
int i; int i;
if (p->num_children && !p->child) { if (p->num_children && !p->child) {
p->child = (struct node_s **)calloc(p->num_children, sizeof(node_t *)); p->child =
if (!p->child) { (struct node_s **)calloc(p->num_children, sizeof(node_t *));
perror("calloc failed"); if (!p->child) {
exit(1); perror("calloc failed");
} exit(1);
} }
for (i = 0; i < p->num_children; i++) }
if (!p->child[i]) { for (i = 0; i < p->num_children; i++)
p->child[i] = all_nodes + n; if (!p->child[i]) {
return; p->child[i] = all_nodes + n;
} return;
}
} }
static int human_fmap(void *p) static int human_fmap(void *p)
{ {
FmapHeader *fmh; FmapHeader *fmh;
FmapAreaHeader *ah; FmapAreaHeader *ah;
int i, j, errorcnt=0; int i, j, errorcnt = 0;
int numnodes; int numnodes;
fmh = (FmapHeader *)p; fmh = (FmapHeader *) p;
ah = (FmapAreaHeader *)(fmh + 1); ah = (FmapAreaHeader *) (fmh + 1);
/* The challenge here is to generate a directed graph from the /* The challenge here is to generate a directed graph from the
* arbitrarily-ordered FMAP entries, and then to prune it until it's as * arbitrarily-ordered FMAP entries, and then to prune it until it's as
* simple (and deep) as possible. Overlapping regions are not allowed. * simple (and deep) as possible. Overlapping regions are not allowed.
* Duplicate regions are okay, but may require special handling. */ * Duplicate regions are okay, but may require special handling. */
/* Convert the FMAP info into our format. */ /* Convert the FMAP info into our format. */
numnodes = fmh->fmap_nareas; numnodes = fmh->fmap_nareas;
/* plus one for the all-enclosing "root" */ /* plus one for the all-enclosing "root" */
all_nodes = (node_t *)calloc(numnodes+1, sizeof(node_t)); all_nodes = (node_t *) calloc(numnodes + 1, sizeof(node_t));
if (!all_nodes) { if (!all_nodes) {
perror("calloc failed"); perror("calloc failed");
exit(1); exit(1);
} }
for (i = 0; i < numnodes; i++) { for (i = 0; i < numnodes; i++) {
char buf[FMAP_NAMELEN+1]; char buf[FMAP_NAMELEN + 1];
strncpy(buf, ah[i].area_name, FMAP_NAMELEN); strncpy(buf, ah[i].area_name, FMAP_NAMELEN);
buf[FMAP_NAMELEN] = '\0'; buf[FMAP_NAMELEN] = '\0';
if (!(all_nodes[i].name = strdup(buf))) { if (!(all_nodes[i].name = strdup(buf))) {
perror("strdup failed"); perror("strdup failed");
exit(1); exit(1);
} }
all_nodes[i].start = ah[i].area_offset; all_nodes[i].start = ah[i].area_offset;
all_nodes[i].size = ah[i].area_size; all_nodes[i].size = ah[i].area_size;
all_nodes[i].end = ah[i].area_offset + ah[i].area_size; all_nodes[i].end = ah[i].area_offset + ah[i].area_size;
} }
/* Now add the root node */ /* Now add the root node */
all_nodes[numnodes].name = strdup("-entire flash-"); all_nodes[numnodes].name = strdup("-entire flash-");
all_nodes[numnodes].start = fmh->fmap_base; all_nodes[numnodes].start = fmh->fmap_base;
all_nodes[numnodes].size = fmh->fmap_size; all_nodes[numnodes].size = fmh->fmap_size;
all_nodes[numnodes].end = fmh->fmap_base + fmh->fmap_size; all_nodes[numnodes].end = fmh->fmap_base + fmh->fmap_size;
/* First, coalesce any duplicates */
for (i = 0; i < numnodes; i++) {
for (j = i + 1; j < numnodes; j++) {
if (duplicates(i, j)) {
add_dupe(i, j, numnodes);
numnodes--;
}
}
}
/* First, coalesce any duplicates */ /* Each node should have at most one parent, which is the smallest
for (i = 0; i < numnodes; i++) { * enclosing node. Duplicate nodes "enclose" each other, but if there's
for (j = i + 1; j < numnodes; j++) { * already a relationship in one direction, we won't create another.
if (duplicates(i, j)) { */
add_dupe(i, j, numnodes); for (i = 0; i < numnodes; i++) {
numnodes--; /* Find the smallest parent, which might be the root node. */
} int k = numnodes;
} for (j = 0; j < numnodes; j++) { /* full O(N^2) comparison */
} if (i == j)
continue;
if (overlaps(i, j)) {
printf("ERROR: %s and %s overlap\n",
all_nodes[i].name, all_nodes[j].name);
printf(" %s: 0x%x - 0x%x\n", all_nodes[i].name,
all_nodes[i].start, all_nodes[i].end);
printf(" %s: 0x%x - 0x%x\n", all_nodes[j].name,
all_nodes[j].start, all_nodes[j].end);
if (opt_overlap < 2) {
printf("Use more -h args to ignore"
" this error\n");
errorcnt++;
}
continue;
}
if (encloses(j, i)
&& all_nodes[j].size < all_nodes[k].size)
k = j;
}
all_nodes[i].parent = all_nodes + k;
}
if (errorcnt)
return 1;
/* Each node should have at most one parent, which is the smallest enclosing /* Force those deadbeat parents to recognize their children */
* node. Duplicate nodes "enclose" each other, but if there's already a for (i = 0; i < numnodes; i++) /* how many */
* relationship in one direction, we won't create another. */ if (all_nodes[i].parent)
for (i = 0; i < numnodes; i++) { all_nodes[i].parent->num_children++;
/* Find the smallest parent, which might be the root node. */ for (i = 0; i < numnodes; i++) /* here they are */
int k = numnodes; if (all_nodes[i].parent)
for (j = 0; j < numnodes; j++) { /* full O(N^2), not triangular */ add_child(all_nodes[i].parent, i);
if (i == j)
continue;
if (overlaps(i, j)) {
printf("ERROR: %s and %s overlap\n",
all_nodes[i].name, all_nodes[j].name);
printf(" %s: 0x%x - 0x%x\n", all_nodes[i].name,
all_nodes[i].start, all_nodes[i].end);
printf(" %s: 0x%x - 0x%x\n", all_nodes[j].name,
all_nodes[j].start, all_nodes[j].end);
if (opt_overlap < 2) {
printf("Use more -h args to ignore this error\n");
errorcnt++;
}
continue;
}
if (encloses(j, i) && all_nodes[j].size < all_nodes[k].size)
k = j;
}
all_nodes[i].parent = all_nodes + k;
}
if (errorcnt)
return 1;
/* Force those deadbeat parents to recognize their children */ /* Ready to go */
for (i = 0; i < numnodes; i++) /* how many */ printf("# name start end size\n");
if (all_nodes[i].parent) show(all_nodes + numnodes, 0, opt_gaps);
all_nodes[i].parent->num_children++;
for (i = 0; i < numnodes; i++) /* here they are */
if (all_nodes[i].parent)
add_child(all_nodes[i].parent, i);
/* Ready to go */ if (gapcount && !opt_gaps)
printf("# name start end size\n"); printf("\nWARNING: unused regions found. Use -H to see them\n");
show(all_nodes + numnodes, 0, opt_gaps);
if (gapcount && !opt_gaps) return 0;
printf("\nWARNING: unused regions found. Use -H to see them\n");
return 0;
} }
/* End of human-reable stuff */ /* End of human-reable stuff */
/****************************************************************************/ /****************************************************************************/
static const char usage[] =
"\nUsage: %s [-x] [-p|-f|-h] FLASHIMAGE [NAME...]\n\n"
"Display (and extract with -x) the FMAP components from a BIOS image.\n"
"The -p option makes the output easier to parse by scripts.\n"
"The -f option emits the FMAP in the format used by flashrom.\n"
"\n"
"Specify one or more NAMEs to only print sections that exactly match.\n"
"\n"
"The -h option shows the whole FMAP in human-readable form.\n"
" Use -H to also display any gaps.\n"
"\n";
static int do_dump_fmap(int argc, char *argv[]) static int do_dump_fmap(int argc, char *argv[])
{ {
int c; int c;
int errorcnt = 0; int errorcnt = 0;
struct stat sb; struct stat sb;
int fd; int fd;
const char *fmap; const char *fmap;
int retval = 1; int retval = 1;
progname = strrchr(argv[0], '/'); progname = strrchr(argv[0], '/');
if (progname) if (progname)
progname++; progname++;
else else
progname = argv[0]; progname = argv[0];
opterr = 0; /* quiet, you */ opterr = 0; /* quiet, you */
while ((c = getopt(argc, argv, ":xpfhH")) != -1) { while ((c = getopt(argc, argv, ":xpfhH")) != -1) {
switch (c) { switch (c) {
case 'x': case 'x':
opt_extract = 1; opt_extract = 1;
break; break;
case 'p': case 'p':
opt_format = FMT_PRETTY; opt_format = FMT_PRETTY;
break; break;
case 'f': case 'f':
opt_format = FMT_FLASHROM; opt_format = FMT_FLASHROM;
break; break;
case 'H': case 'H':
opt_gaps = 1; opt_gaps = 1;
/* fallthrough */ /* fallthrough */
case 'h': case 'h':
opt_format = FMT_HUMAN; opt_format = FMT_HUMAN;
opt_overlap++; opt_overlap++;
break; break;
case '?': case '?':
fprintf(stderr, "%s: unrecognized switch: -%c\n", fprintf(stderr, "%s: unrecognized switch: -%c\n",
progname, optopt); progname, optopt);
errorcnt++; errorcnt++;
break; break;
case ':': case ':':
fprintf(stderr, "%s: missing argument to -%c\n", fprintf(stderr, "%s: missing argument to -%c\n",
progname, optopt); progname, optopt);
errorcnt++; errorcnt++;
break; break;
default: default:
errorcnt++; errorcnt++;
break; break;
} }
} }
if (errorcnt || optind >= argc) { if (errorcnt || optind >= argc) {
fprintf(stderr, fprintf(stderr, usage, progname);
"\nUsage: %s [-x] [-p|-f|-h] FLASHIMAGE [NAME...]\n\n" return 1;
"Display (and extract with -x) the FMAP components from a BIOS image.\n" }
"The -p option makes the output easier to parse by scripts.\n"
"The -f option emits the FMAP in the format used by flashrom.\n"
"\n"
"Specify one or more NAMEs to only print sections that exactly match.\n"
"\n"
"The -h option shows the whole FMAP in human-readable form.\n"
" Use -H to also display any gaps.\n"
"\n",
progname);
return 1;
}
if (0 != stat(argv[optind], &sb)) { if (0 != stat(argv[optind], &sb)) {
fprintf(stderr, "%s: can't stat %s: %s\n", fprintf(stderr, "%s: can't stat %s: %s\n",
progname, progname, argv[optind], strerror(errno));
argv[optind], return 1;
strerror(errno)); }
return 1;
}
fd = open(argv[optind], O_RDONLY); fd = open(argv[optind], O_RDONLY);
if (fd < 0) { if (fd < 0) {
fprintf(stderr, "%s: can't open %s: %s\n", fprintf(stderr, "%s: can't open %s: %s\n",
progname, progname, argv[optind], strerror(errno));
argv[optind], return 1;
strerror(errno)); }
return 1;
}
base_of_rom = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); base_of_rom =
if (base_of_rom == (char*)-1) { mmap(0, sb.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
fprintf(stderr, "%s: can't mmap %s: %s\n", if (base_of_rom == (char *)-1) {
progname, fprintf(stderr, "%s: can't mmap %s: %s\n",
argv[optind], progname, argv[optind], strerror(errno));
strerror(errno)); close(fd);
close(fd); return 1;
return 1; }
} close(fd); /* done with this now */
close(fd); /* done with this now */ size_of_rom = sb.st_size;
size_of_rom = sb.st_size;
fmap = FmapFind((char*) base_of_rom, size_of_rom); fmap = FmapFind((char *)base_of_rom, size_of_rom);
if (fmap) { if (fmap) {
switch (opt_format) { switch (opt_format) {
case FMT_HUMAN: case FMT_HUMAN:
retval = human_fmap((void *)fmap); retval = human_fmap((void *)fmap);
break; break;
case FMT_NORMAL: case FMT_NORMAL:
printf("hit at 0x%08x\n", (uint32_t) (fmap - (char*) base_of_rom)); printf("hit at 0x%08x\n",
/* fallthrough */ (uint32_t) (fmap - (char *)base_of_rom));
default: /* fallthrough */
retval = dump_fmap(fmap, argc-optind-1, argv+optind+1); default:
} retval =
} dump_fmap(fmap, argc - optind - 1,
argv + optind + 1);
}
}
if (0 != munmap(base_of_rom, sb.st_size)) { if (0 != munmap(base_of_rom, sb.st_size)) {
fprintf(stderr, "%s: can't munmap %s: %s\n", fprintf(stderr, "%s: can't munmap %s: %s\n",
progname, progname, argv[optind], strerror(errno));
argv[optind], return 1;
strerror(errno)); }
return 1;
}
return retval; return retval;
} }
DECLARE_FUTIL_COMMAND(dump_fmap, do_dump_fmap, DECLARE_FUTIL_COMMAND(dump_fmap, do_dump_fmap,
"Display FMAP contents from a firmware image"); "Display FMAP contents from a firmware image");

View File

@@ -5,7 +5,6 @@
* Exports the kernel commandline from a given partition/image. * Exports the kernel commandline from a given partition/image.
*/ */
#include <getopt.h> #include <getopt.h>
#include <stdio.h> #include <stdio.h>
#include <sys/mman.h> #include <sys/mman.h>
@@ -15,78 +14,78 @@
#include "vboot_host.h" #include "vboot_host.h"
enum { enum {
OPT_KLOADADDR = 1000, OPT_KLOADADDR = 1000,
}; };
static const struct option long_opts[] = { static const struct option long_opts[] = {
{ "kloadaddr", 1, NULL, OPT_KLOADADDR }, {"kloadaddr", 1, NULL, OPT_KLOADADDR},
{ NULL, 0, NULL, 0 } {NULL, 0, NULL, 0}
}; };
/* Print help and return error */ /* Print help and return error */
static int PrintHelp(void) { static int PrintHelp(void)
puts("dump_kernel_config - Prints the kernel command line\n" {
"\n" puts("dump_kernel_config - Prints the kernel command line\n"
"Usage: dump_kernel_config [--kloadaddr <ADDRESS>] " "\n"
"<image/blockdevice>\n" "Usage: dump_kernel_config [--kloadaddr <ADDRESS>] "
"\n" "<image/blockdevice>\n" "\n" "");
""); return 1;
return 1;
} }
static int do_dump_kernel_config(int argc, char* argv[]) { static int do_dump_kernel_config(int argc, char *argv[])
char *infile = NULL; {
char *config = NULL; char *infile = NULL;
uint64_t kernel_body_load_address = USE_PREAMBLE_LOAD_ADDR; char *config = NULL;
int parse_error = 0; uint64_t kernel_body_load_address = USE_PREAMBLE_LOAD_ADDR;
char *e; int parse_error = 0;
int i; char *e;
int i;
while (((i = getopt_long(argc, argv, ":", long_opts, NULL)) != -1) && while (((i = getopt_long(argc, argv, ":", long_opts, NULL)) != -1) &&
!parse_error) { !parse_error) {
switch (i) { switch (i) {
default: default:
case '?': case '?':
/* Unhandled option */ /* Unhandled option */
parse_error = 1; parse_error = 1;
break; break;
case 0: case 0:
/* silently handled option */ /* silently handled option */
break; break;
case OPT_KLOADADDR: case OPT_KLOADADDR:
kernel_body_load_address = strtoul(optarg, &e, 0); kernel_body_load_address = strtoul(optarg, &e, 0);
if (!*optarg || (e && *e)) { if (!*optarg || (e && *e)) {
fprintf(stderr, "Invalid --kloadaddr\n"); fprintf(stderr, "Invalid --kloadaddr\n");
parse_error = 1; parse_error = 1;
} }
break; break;
} }
} }
if (optind >= argc) { if (optind >= argc) {
fprintf(stderr, "Expected argument after options\n"); fprintf(stderr, "Expected argument after options\n");
parse_error = 1; parse_error = 1;
} else } else
infile = argv[optind]; infile = argv[optind];
if (parse_error) if (parse_error)
return PrintHelp(); return PrintHelp();
if (!infile || !*infile) { if (!infile || !*infile) {
fprintf(stderr, "Must specify filename\n"); fprintf(stderr, "Must specify filename\n");
return 1; return 1;
} }
config = FindKernelConfig(infile, kernel_body_load_address); config = FindKernelConfig(infile, kernel_body_load_address);
if (!config) if (!config)
return 1; return 1;
printf("%s", config); printf("%s", config);
free(config); free(config);
return 0; return 0;
} }
DECLARE_FUTIL_COMMAND(dump_kernel_config, do_dump_kernel_config, DECLARE_FUTIL_COMMAND(dump_kernel_config, do_dump_kernel_config,

File diff suppressed because it is too large Load Diff

View File

@@ -6,7 +6,7 @@
*/ */
#include <getopt.h> #include <getopt.h>
#include <inttypes.h> /* For PRIu64 */ #include <inttypes.h> /* For PRIu64 */
#include <stddef.h> #include <stddef.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@@ -19,358 +19,368 @@
#include "util_misc.h" #include "util_misc.h"
#include "vboot_common.h" #include "vboot_common.h"
/* Command line options */ /* Command line options */
enum { enum {
OPT_MODE_VBLOCK = 1000, OPT_MODE_VBLOCK = 1000,
OPT_MODE_VERIFY, OPT_MODE_VERIFY,
OPT_KEYBLOCK, OPT_KEYBLOCK,
OPT_SIGNPUBKEY, OPT_SIGNPUBKEY,
OPT_SIGNPRIVATE, OPT_SIGNPRIVATE,
OPT_VERSION, OPT_VERSION,
OPT_FV, OPT_FV,
OPT_KERNELKEY, OPT_KERNELKEY,
OPT_FLAGS, OPT_FLAGS,
}; };
static const struct option long_opts[] = { static const struct option long_opts[] = {
{"vblock", 1, 0, OPT_MODE_VBLOCK }, {"vblock", 1, 0, OPT_MODE_VBLOCK},
{"verify", 1, 0, OPT_MODE_VERIFY }, {"verify", 1, 0, OPT_MODE_VERIFY},
{"keyblock", 1, 0, OPT_KEYBLOCK }, {"keyblock", 1, 0, OPT_KEYBLOCK},
{"signpubkey", 1, 0, OPT_SIGNPUBKEY }, {"signpubkey", 1, 0, OPT_SIGNPUBKEY},
{"signprivate", 1, 0, OPT_SIGNPRIVATE }, {"signprivate", 1, 0, OPT_SIGNPRIVATE},
{"version", 1, 0, OPT_VERSION }, {"version", 1, 0, OPT_VERSION},
{"fv", 1, 0, OPT_FV }, {"fv", 1, 0, OPT_FV},
{"kernelkey", 1, 0, OPT_KERNELKEY }, {"kernelkey", 1, 0, OPT_KERNELKEY},
{"flags", 1, 0, OPT_FLAGS }, {"flags", 1, 0, OPT_FLAGS},
{NULL, 0, 0, 0} {NULL, 0, 0, 0}
}; };
/* Print help and return error */ /* Print help and return error */
static int PrintHelp(void) { static int PrintHelp(void)
{
puts("vbutil_firmware - Verified boot key block utility\n" puts("vbutil_firmware - Verified boot key block utility\n"
"\n" "\n"
"Usage: vbutil_firmware <--vblock|--verify> <file> [OPTIONS]\n" "Usage: vbutil_firmware <--vblock|--verify> <file> [OPTIONS]\n"
"\n" "\n"
"For '--vblock <file>', required OPTIONS are:\n" "For '--vblock <file>', required OPTIONS are:\n"
" --keyblock <file> Key block in .keyblock format\n" " --keyblock <file> Key block in .keyblock format\n"
" --signprivate <file> Signing private key in .vbprivk format\n" " --signprivate <file>"
" --version <number> Firmware version\n" " Signing private key in .vbprivk format\n"
" --fv <file> Firmware volume to sign\n" " --version <number> Firmware version\n"
" --kernelkey <file> Kernel subkey in .vbpubk format\n" " --fv <file> Firmware volume to sign\n"
"optional OPTIONS are:\n" " --kernelkey <file> Kernel subkey in .vbpubk format\n"
" --flags <number> Preamble flags (defaults to 0)\n" "optional OPTIONS are:\n"
"\n" " --flags <number> Preamble flags (defaults to 0)\n"
"For '--verify <file>', required OPTIONS are:\n" "\n"
" --signpubkey <file> Signing public key in .vbpubk format\n" "For '--verify <file>', required OPTIONS are:\n"
" --fv <file> Firmware volume to verify\n" " --signpubkey <file>"
"\n" " Signing public key in .vbpubk format\n"
"For '--verify <file>', optional OPTIONS are:\n" " --fv <file> Firmware volume to verify\n"
" --kernelkey <file> Write the kernel subkey to this file\n" "\n"
""); "For '--verify <file>', optional OPTIONS are:\n"
return 1; " --kernelkey <file>"
" Write the kernel subkey to this file\n"
"");
return 1;
} }
/* Create a firmware .vblock */ /* Create a firmware .vblock */
static int Vblock(const char* outfile, const char* keyblock_file, static int Vblock(const char *outfile, const char *keyblock_file,
const char* signprivate, uint64_t version, const char *signprivate, uint64_t version,
const char* fv_file, const char* kernelkey_file, const char *fv_file, const char *kernelkey_file,
uint32_t preamble_flags) { uint32_t preamble_flags)
{
VbPrivateKey* signing_key; VbPrivateKey *signing_key;
VbPublicKey* kernel_subkey; VbPublicKey *kernel_subkey;
VbSignature* body_sig; VbSignature *body_sig;
VbFirmwarePreambleHeader* preamble; VbFirmwarePreambleHeader *preamble;
VbKeyBlockHeader* key_block; VbKeyBlockHeader *key_block;
uint64_t key_block_size; uint64_t key_block_size;
uint8_t* fv_data; uint8_t *fv_data;
uint64_t fv_size; uint64_t fv_size;
FILE* f; FILE *f;
uint64_t i; uint64_t i;
if (!outfile) { if (!outfile) {
VbExError("Must specify output filename\n"); VbExError("Must specify output filename\n");
return 1; return 1;
} }
if (!keyblock_file || !signprivate || !kernelkey_file) { if (!keyblock_file || !signprivate || !kernelkey_file) {
VbExError("Must specify all keys\n"); VbExError("Must specify all keys\n");
return 1; return 1;
} }
if (!fv_file) { if (!fv_file) {
VbExError("Must specify firmware volume\n"); VbExError("Must specify firmware volume\n");
return 1; return 1;
} }
/* Read the key block and keys */ /* Read the key block and keys */
key_block = (VbKeyBlockHeader*)ReadFile(keyblock_file, &key_block_size); key_block =
if (!key_block) { (VbKeyBlockHeader *) ReadFile(keyblock_file, &key_block_size);
VbExError("Error reading key block.\n"); if (!key_block) {
return 1; VbExError("Error reading key block.\n");
} return 1;
}
signing_key = PrivateKeyRead(signprivate); signing_key = PrivateKeyRead(signprivate);
if (!signing_key) { if (!signing_key) {
VbExError("Error reading signing key.\n"); VbExError("Error reading signing key.\n");
return 1; return 1;
} }
kernel_subkey = PublicKeyRead(kernelkey_file); kernel_subkey = PublicKeyRead(kernelkey_file);
if (!kernel_subkey) { if (!kernel_subkey) {
VbExError("Error reading kernel subkey.\n"); VbExError("Error reading kernel subkey.\n");
return 1; return 1;
} }
/* Read and sign the firmware volume */ /* Read and sign the firmware volume */
fv_data = ReadFile(fv_file, &fv_size); fv_data = ReadFile(fv_file, &fv_size);
if (!fv_data) if (!fv_data)
return 1; return 1;
if (!fv_size) { if (!fv_size) {
VbExError("Empty firmware volume file\n"); VbExError("Empty firmware volume file\n");
return 1; return 1;
} }
body_sig = CalculateSignature(fv_data, fv_size, signing_key); body_sig = CalculateSignature(fv_data, fv_size, signing_key);
if (!body_sig) { if (!body_sig) {
VbExError("Error calculating body signature\n"); VbExError("Error calculating body signature\n");
return 1; return 1;
} }
free(fv_data); free(fv_data);
/* Create preamble */ /* Create preamble */
preamble = CreateFirmwarePreamble(version, preamble = CreateFirmwarePreamble(version,
kernel_subkey, kernel_subkey,
body_sig, body_sig,
signing_key, signing_key, preamble_flags);
preamble_flags); if (!preamble) {
if (!preamble) { VbExError("Error creating preamble.\n");
VbExError("Error creating preamble.\n"); return 1;
return 1; }
}
/* Write the output file */ /* Write the output file */
f = fopen(outfile, "wb"); f = fopen(outfile, "wb");
if (!f) { if (!f) {
VbExError("Can't open output file %s\n", outfile); VbExError("Can't open output file %s\n", outfile);
return 1; return 1;
} }
i = ((1 != fwrite(key_block, key_block_size, 1, f)) || i = ((1 != fwrite(key_block, key_block_size, 1, f)) ||
(1 != fwrite(preamble, preamble->preamble_size, 1, f))); (1 != fwrite(preamble, preamble->preamble_size, 1, f)));
fclose(f); fclose(f);
if (i) { if (i) {
VbExError("Can't write output file %s\n", outfile); VbExError("Can't write output file %s\n", outfile);
unlink(outfile); unlink(outfile);
return 1; return 1;
} }
/* Success */ /* Success */
return 0; return 0;
} }
static int Verify(const char* infile, const char* signpubkey, static int Verify(const char *infile, const char *signpubkey,
const char* fv_file, const char* kernelkey_file) { const char *fv_file, const char *kernelkey_file)
{
VbKeyBlockHeader* key_block; VbKeyBlockHeader *key_block;
VbFirmwarePreambleHeader* preamble; VbFirmwarePreambleHeader *preamble;
VbPublicKey* data_key; VbPublicKey *data_key;
VbPublicKey* sign_key; VbPublicKey *sign_key;
VbPublicKey* kernel_subkey; VbPublicKey *kernel_subkey;
RSAPublicKey* rsa; RSAPublicKey *rsa;
uint8_t* blob; uint8_t *blob;
uint64_t blob_size; uint64_t blob_size;
uint8_t* fv_data; uint8_t *fv_data;
uint64_t fv_size; uint64_t fv_size;
uint64_t now = 0; uint64_t now = 0;
uint32_t flags; uint32_t flags;
if (!infile || !signpubkey || !fv_file) { if (!infile || !signpubkey || !fv_file) {
VbExError("Must specify filename, signpubkey, and fv\n"); VbExError("Must specify filename, signpubkey, and fv\n");
return 1; return 1;
} }
/* Read public signing key */ /* Read public signing key */
sign_key = PublicKeyRead(signpubkey); sign_key = PublicKeyRead(signpubkey);
if (!sign_key) { if (!sign_key) {
VbExError("Error reading signpubkey.\n"); VbExError("Error reading signpubkey.\n");
return 1; return 1;
} }
/* Read blob */ /* Read blob */
blob = ReadFile(infile, &blob_size); blob = ReadFile(infile, &blob_size);
if (!blob) { if (!blob) {
VbExError("Error reading input file\n"); VbExError("Error reading input file\n");
return 1; return 1;
} }
/* Read firmware volume */ /* Read firmware volume */
fv_data = ReadFile(fv_file, &fv_size); fv_data = ReadFile(fv_file, &fv_size);
if (!fv_data) { if (!fv_data) {
VbExError("Error reading firmware volume\n"); VbExError("Error reading firmware volume\n");
return 1; return 1;
} }
/* Verify key block */ /* Verify key block */
key_block = (VbKeyBlockHeader*)blob; key_block = (VbKeyBlockHeader *) blob;
if (0 != KeyBlockVerify(key_block, blob_size, sign_key, 0)) { if (0 != KeyBlockVerify(key_block, blob_size, sign_key, 0)) {
VbExError("Error verifying key block.\n"); VbExError("Error verifying key block.\n");
return 1; return 1;
} }
free(sign_key); free(sign_key);
now += key_block->key_block_size; now += key_block->key_block_size;
printf("Key block:\n"); printf("Key block:\n");
data_key = &key_block->data_key; data_key = &key_block->data_key;
printf(" Size: %" PRIu64 "\n", key_block->key_block_size); printf(" Size: %" PRIu64 "\n",
printf(" Flags: %" PRIu64 " (ignored)\n", key_block->key_block_size);
key_block->key_block_flags); printf(" Flags: %" PRIu64 " (ignored)\n",
printf(" Data key algorithm: %" PRIu64 " %s\n", data_key->algorithm, key_block->key_block_flags);
(data_key->algorithm < kNumAlgorithms ? printf(" Data key algorithm: %" PRIu64 " %s\n", data_key->algorithm,
algo_strings[data_key->algorithm] : "(invalid)")); (data_key->algorithm <
printf(" Data key version: %" PRIu64 "\n", data_key->key_version); kNumAlgorithms ? algo_strings[data_key->
printf(" Data key sha1sum: "); algorithm] : "(invalid)"));
PrintPubKeySha1Sum(data_key); printf(" Data key version: %" PRIu64 "\n", data_key->key_version);
printf("\n"); printf(" Data key sha1sum: ");
PrintPubKeySha1Sum(data_key);
printf("\n");
rsa = PublicKeyToRSA(&key_block->data_key); rsa = PublicKeyToRSA(&key_block->data_key);
if (!rsa) { if (!rsa) {
VbExError("Error parsing data key.\n"); VbExError("Error parsing data key.\n");
return 1; return 1;
} }
/* Verify preamble */ /* Verify preamble */
preamble = (VbFirmwarePreambleHeader*)(blob + now); preamble = (VbFirmwarePreambleHeader *) (blob + now);
if (0 != VerifyFirmwarePreamble(preamble, blob_size - now, rsa)) { if (0 != VerifyFirmwarePreamble(preamble, blob_size - now, rsa)) {
VbExError("Error verifying preamble.\n"); VbExError("Error verifying preamble.\n");
return 1; return 1;
} }
now += preamble->preamble_size; now += preamble->preamble_size;
flags = VbGetFirmwarePreambleFlags(preamble); flags = VbGetFirmwarePreambleFlags(preamble);
printf("Preamble:\n"); printf("Preamble:\n");
printf(" Size: %" PRIu64 "\n", preamble->preamble_size); printf(" Size: %" PRIu64 "\n",
printf(" Header version: %" PRIu32 ".%" PRIu32"\n", preamble->preamble_size);
preamble->header_version_major, preamble->header_version_minor); printf(" Header version: %" PRIu32 ".%" PRIu32 "\n",
printf(" Firmware version: %" PRIu64 "\n", preamble->firmware_version); preamble->header_version_major, preamble->header_version_minor);
kernel_subkey = &preamble->kernel_subkey; printf(" Firmware version: %" PRIu64 "\n",
printf(" Kernel key algorithm: %" PRIu64 " %s\n", preamble->firmware_version);
kernel_subkey->algorithm, kernel_subkey = &preamble->kernel_subkey;
(kernel_subkey->algorithm < kNumAlgorithms ? printf(" Kernel key algorithm: %" PRIu64 " %s\n",
algo_strings[kernel_subkey->algorithm] : "(invalid)")); kernel_subkey->algorithm,
printf(" Kernel key version: %" PRIu64 "\n", (kernel_subkey->algorithm < kNumAlgorithms ?
kernel_subkey->key_version); algo_strings[kernel_subkey->algorithm] : "(invalid)"));
printf(" Kernel key sha1sum: "); printf(" Kernel key version: %" PRIu64 "\n",
PrintPubKeySha1Sum(kernel_subkey); kernel_subkey->key_version);
printf("\n"); printf(" Kernel key sha1sum: ");
printf(" Firmware body size: %" PRIu64 "\n", PrintPubKeySha1Sum(kernel_subkey);
preamble->body_signature.data_size); printf("\n");
printf(" Preamble flags: %" PRIu32 "\n", flags); printf(" Firmware body size: %" PRIu64 "\n",
preamble->body_signature.data_size);
printf(" Preamble flags: %" PRIu32 "\n", flags);
/* TODO: verify body size same as signature size */ /* TODO: verify body size same as signature size */
/* Verify body */ /* Verify body */
if (flags & VB_FIRMWARE_PREAMBLE_USE_RO_NORMAL) { if (flags & VB_FIRMWARE_PREAMBLE_USE_RO_NORMAL) {
printf("Preamble requests USE_RO_NORMAL; skipping body verification.\n"); printf
} else { ("Preamble requests USE_RO_NORMAL;"
if (0 != VerifyData(fv_data, fv_size, &preamble->body_signature, rsa)) { " skipping body verification.\n");
VbExError("Error verifying firmware body.\n"); } else {
return 1; if (0 !=
} VerifyData(fv_data, fv_size, &preamble->body_signature,
printf("Body verification succeeded.\n"); rsa)) {
} VbExError("Error verifying firmware body.\n");
return 1;
}
printf("Body verification succeeded.\n");
}
if (kernelkey_file) { if (kernelkey_file) {
if (0 != PublicKeyWrite(kernelkey_file, kernel_subkey)) { if (0 != PublicKeyWrite(kernelkey_file, kernel_subkey)) {
fprintf(stderr, VbExError("Unable to write kernel subkey\n");
"vbutil_firmware: unable to write kernel subkey\n"); return 1;
return 1; }
} }
}
return 0; return 0;
} }
static int do_vbutil_firmware(int argc, char *argv[])
{
static int do_vbutil_firmware(int argc, char* argv[]) { char *filename = NULL;
char *key_block_file = NULL;
char *signpubkey = NULL;
char *signprivate = NULL;
uint64_t version = 0;
char *fv_file = NULL;
char *kernelkey_file = NULL;
uint32_t preamble_flags = 0;
int mode = 0;
int parse_error = 0;
char *e;
int i;
char* filename = NULL; while ((i = getopt_long(argc, argv, "", long_opts, NULL)) != -1) {
char* key_block_file = NULL; switch (i) {
char* signpubkey = NULL; case '?':
char* signprivate = NULL; /* Unhandled option */
uint64_t version = 0; printf("Unknown option\n");
char* fv_file = NULL; parse_error = 1;
char* kernelkey_file = NULL; break;
uint32_t preamble_flags = 0;
int mode = 0;
int parse_error = 0;
char* e;
int i;
while ((i = getopt_long(argc, argv, "", long_opts, NULL)) != -1) { case OPT_MODE_VBLOCK:
switch (i) { case OPT_MODE_VERIFY:
case '?': mode = i;
/* Unhandled option */ filename = optarg;
printf("Unknown option\n"); break;
parse_error = 1;
break;
case OPT_MODE_VBLOCK: case OPT_KEYBLOCK:
case OPT_MODE_VERIFY: key_block_file = optarg;
mode = i; break;
filename = optarg;
break;
case OPT_KEYBLOCK: case OPT_SIGNPUBKEY:
key_block_file = optarg; signpubkey = optarg;
break; break;
case OPT_SIGNPUBKEY: case OPT_SIGNPRIVATE:
signpubkey = optarg; signprivate = optarg;
break; break;
case OPT_SIGNPRIVATE: case OPT_FV:
signprivate = optarg; fv_file = optarg;
break; break;
case OPT_FV: case OPT_KERNELKEY:
fv_file = optarg; kernelkey_file = optarg;
break; break;
case OPT_KERNELKEY: case OPT_VERSION:
kernelkey_file = optarg; version = strtoul(optarg, &e, 0);
break; if (!*optarg || (e && *e)) {
printf("Invalid --version\n");
parse_error = 1;
}
break;
case OPT_VERSION: case OPT_FLAGS:
version = strtoul(optarg, &e, 0); preamble_flags = strtoul(optarg, &e, 0);
if (!*optarg || (e && *e)) { if (!*optarg || (e && *e)) {
printf("Invalid --version\n"); printf("Invalid --flags\n");
parse_error = 1; parse_error = 1;
} }
break; break;
}
}
case OPT_FLAGS: if (parse_error)
preamble_flags = strtoul(optarg, &e, 0); return PrintHelp();
if (!*optarg || (e && *e)) {
printf("Invalid --flags\n");
parse_error = 1;
}
break;
}
}
if (parse_error) switch (mode) {
return PrintHelp(); case OPT_MODE_VBLOCK:
return Vblock(filename, key_block_file, signprivate, version,
switch(mode) { fv_file, kernelkey_file, preamble_flags);
case OPT_MODE_VBLOCK: case OPT_MODE_VERIFY:
return Vblock(filename, key_block_file, signprivate, version, fv_file, return Verify(filename, signpubkey, fv_file, kernelkey_file);
kernelkey_file, preamble_flags); default:
case OPT_MODE_VERIFY: printf("Must specify a mode.\n");
return Verify(filename, signpubkey, fv_file, kernelkey_file); return PrintHelp();
default: }
printf("Must specify a mode.\n");
return PrintHelp();
}
} }
DECLARE_FUTIL_COMMAND(vbutil_firmware, do_vbutil_firmware, DECLARE_FUTIL_COMMAND(vbutil_firmware, do_vbutil_firmware,

File diff suppressed because it is too large Load Diff

View File

@@ -6,7 +6,7 @@
*/ */
#include <getopt.h> #include <getopt.h>
#include <inttypes.h> /* For PRIu64 */ #include <inttypes.h> /* For PRIu64 */
#include <stdarg.h> #include <stdarg.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@@ -18,224 +18,227 @@
#include "util_misc.h" #include "util_misc.h"
#include "vboot_common.h" #include "vboot_common.h"
/* Command line options */ /* Command line options */
enum { enum {
OPT_INKEY = 1000, OPT_INKEY = 1000,
OPT_KEY_VERSION, OPT_KEY_VERSION,
OPT_ALGORITHM, OPT_ALGORITHM,
OPT_MODE_PACK, OPT_MODE_PACK,
OPT_MODE_UNPACK, OPT_MODE_UNPACK,
OPT_COPYTO, OPT_COPYTO,
}; };
static const struct option long_opts[] = { static const struct option long_opts[] = {
{"key", 1, 0, OPT_INKEY }, {"key", 1, 0, OPT_INKEY},
{"version", 1, 0, OPT_KEY_VERSION }, {"version", 1, 0, OPT_KEY_VERSION},
{"algorithm", 1, 0, OPT_ALGORITHM }, {"algorithm", 1, 0, OPT_ALGORITHM},
{"pack", 1, 0, OPT_MODE_PACK }, {"pack", 1, 0, OPT_MODE_PACK},
{"unpack", 1, 0, OPT_MODE_UNPACK }, {"unpack", 1, 0, OPT_MODE_UNPACK},
{"copyto", 1, 0, OPT_COPYTO }, {"copyto", 1, 0, OPT_COPYTO},
{NULL, 0, 0, 0} {NULL, 0, 0, 0}
}; };
/* Print help and return error */ /* Print help and return error */
static int PrintHelp(char *progname) { static int PrintHelp(char *progname)
int i; {
int i;
fprintf(stderr, fprintf(stderr,
"This program wraps RSA keys with verified boot headers\n"); "This program wraps RSA keys with verified boot headers\n");
fprintf(stderr, fprintf(stderr,
"\n" "\n"
"Usage: %s --pack <outfile> [PARAMETERS]\n" "Usage: %s --pack <outfile> [PARAMETERS]\n"
"\n" "\n"
" Required parameters:\n" " Required parameters:\n"
" --key <infile> RSA key file (.keyb or .pem)\n" " --key <infile> RSA key file (.keyb or .pem)\n"
" --version <number> Key version number " " --version <number> Key version number "
"(required for .keyb,\n" "(required for .keyb,\n"
" ignored for .pem)\n" " ignored for .pem)\n"
" --algorithm <number> " " --algorithm <number> "
"Signing algorithm to use with key:\n", "Signing algorithm to use with key:\n", progname);
progname);
for (i = 0; i < kNumAlgorithms; i++) { for (i = 0; i < kNumAlgorithms; i++) {
fprintf(stderr, fprintf(stderr,
" %d = (%s)\n", " %d = (%s)\n",
i, algo_strings[i]); i, algo_strings[i]);
} }
fprintf(stderr, fprintf(stderr,
"\nOR\n\n" "\nOR\n\n"
"Usage: %s --unpack <infile>\n" "Usage: %s --unpack <infile>\n"
"\n" "\n"
" Optional parameters:\n" " Optional parameters:\n"
" --copyto <file> " " --copyto <file> "
"Write a copy of the key to this file.\n" "Write a copy of the key to this file.\n" "\n", progname);
"\n",
progname);
return 1; return 1;
} }
/* Pack a .keyb file into a .vbpubk, or a .pem into a .vbprivk */ /* Pack a .keyb file into a .vbpubk, or a .pem into a .vbprivk */
static int Pack(const char *infile, const char *outfile, uint64_t algorithm, static int Pack(const char *infile, const char *outfile, uint64_t algorithm,
uint64_t version) { uint64_t version)
VbPublicKey* pubkey; {
VbPrivateKey* privkey; VbPublicKey *pubkey;
VbPrivateKey *privkey;
if (!infile || !outfile) { if (!infile || !outfile) {
fprintf(stderr, "vbutil_key: Must specify --in and --out\n"); fprintf(stderr, "vbutil_key: Must specify --in and --out\n");
return 1; return 1;
} }
if ((pubkey = PublicKeyReadKeyb(infile, algorithm, version))) { if ((pubkey = PublicKeyReadKeyb(infile, algorithm, version))) {
if (0 != PublicKeyWrite(outfile, pubkey)) { if (0 != PublicKeyWrite(outfile, pubkey)) {
fprintf(stderr, "vbutil_key: Error writing key.\n"); fprintf(stderr, "vbutil_key: Error writing key.\n");
return 1; return 1;
} }
free(pubkey); free(pubkey);
return 0; return 0;
} }
if ((privkey = PrivateKeyReadPem(infile, algorithm))) { if ((privkey = PrivateKeyReadPem(infile, algorithm))) {
if (0 != PrivateKeyWrite(outfile, privkey)) { if (0 != PrivateKeyWrite(outfile, privkey)) {
fprintf(stderr, "vbutil_key: Error writing key.\n"); fprintf(stderr, "vbutil_key: Error writing key.\n");
return 1; return 1;
} }
free(privkey); free(privkey);
return 0; return 0;
} }
VbExError("Unable to parse either .keyb or .pem from %s\n", infile); VbExError("Unable to parse either .keyb or .pem from %s\n", infile);
return 1; return 1;
} }
/* Unpack a .vbpubk or .vbprivk */ /* Unpack a .vbpubk or .vbprivk */
static int Unpack(const char *infile, const char *outfile) { static int Unpack(const char *infile, const char *outfile)
VbPublicKey* pubkey; {
VbPrivateKey* privkey; VbPublicKey *pubkey;
VbPrivateKey *privkey;
if (!infile) { if (!infile) {
fprintf(stderr, "Need file to unpack\n"); fprintf(stderr, "Need file to unpack\n");
return 1; return 1;
} }
if ((pubkey = PublicKeyRead(infile))) { if ((pubkey = PublicKeyRead(infile))) {
printf("Public Key file: %s\n", infile); printf("Public Key file: %s\n", infile);
printf("Algorithm: %" PRIu64 " %s\n", pubkey->algorithm, printf("Algorithm: %" PRIu64 " %s\n", pubkey->algorithm,
(pubkey->algorithm < kNumAlgorithms ? (pubkey->algorithm < kNumAlgorithms ?
algo_strings[pubkey->algorithm] : "(invalid)")); algo_strings[pubkey->algorithm] : "(invalid)"));
printf("Key Version: %" PRIu64 "\n", pubkey->key_version); printf("Key Version: %" PRIu64 "\n", pubkey->key_version);
printf("Key sha1sum: "); printf("Key sha1sum: ");
PrintPubKeySha1Sum(pubkey); PrintPubKeySha1Sum(pubkey);
printf("\n"); printf("\n");
if (outfile) { if (outfile) {
if (0 != PublicKeyWrite(outfile, pubkey)) { if (0 != PublicKeyWrite(outfile, pubkey)) {
fprintf(stderr, "vbutil_key: Error writing key copy.\n"); fprintf(stderr,
free(pubkey); "vbutil_key: Error writing key copy\n");
return 1; free(pubkey);
} return 1;
} }
free(pubkey); }
return 0; free(pubkey);
} return 0;
}
if ((privkey = PrivateKeyRead(infile))) { if ((privkey = PrivateKeyRead(infile))) {
printf("Private Key file: %s\n", infile); printf("Private Key file: %s\n", infile);
printf("Algorithm: %" PRIu64 " %s\n", privkey->algorithm, printf("Algorithm: %" PRIu64 " %s\n",
(privkey->algorithm < kNumAlgorithms ? privkey->algorithm,
algo_strings[privkey->algorithm] : "(invalid)")); (privkey->algorithm <
if (outfile) { kNumAlgorithms ? algo_strings[privkey->
if (0 != PrivateKeyWrite(outfile, privkey)) { algorithm] :
fprintf(stderr, "vbutil_key: Error writing key copy.\n"); "(invalid)"));
free(privkey); if (outfile) {
return 1; if (0 != PrivateKeyWrite(outfile, privkey)) {
} fprintf(stderr,
} "vbutil_key: Error writing key copy\n");
free(privkey); free(privkey);
return 0; return 1;
} }
}
free(privkey);
return 0;
}
VbExError("Unable to parse either .vbpubk or vbprivk from %s\n", infile); VbExError("Unable to parse either .vbpubk or vbprivk from %s\n",
return 1; infile);
return 1;
} }
static int do_vbutil_key(int argc, char *argv[])
{
static int do_vbutil_key(int argc, char* argv[]) { char *infile = NULL;
char *outfile = NULL;
int mode = 0;
int parse_error = 0;
uint64_t version = 1;
uint64_t algorithm = kNumAlgorithms;
char *e;
int i;
char *infile = NULL; char *progname = strrchr(argv[0], '/');
char *outfile = NULL; if (progname)
int mode = 0; progname++;
int parse_error = 0; else
uint64_t version = 1; progname = argv[0];
uint64_t algorithm = kNumAlgorithms;
char* e;
int i;
char *progname = strrchr(argv[0], '/'); while ((i = getopt_long(argc, argv, "", long_opts, NULL)) != -1) {
if (progname) switch (i) {
progname++; case '?':
else /* Unhandled option */
progname = argv[0]; VbExError("Unknown option\n");
parse_error = 1;
break;
while ((i = getopt_long(argc, argv, "", long_opts, NULL)) != -1) { case OPT_INKEY:
switch (i) { infile = optarg;
case '?': break;
/* Unhandled option */
VbExError("Unknown option\n");
parse_error = 1;
break;
case OPT_INKEY: case OPT_KEY_VERSION:
infile = optarg; version = strtoul(optarg, &e, 0);
break; if (!*optarg || (e && *e)) {
VbExError("Invalid --version\n");
parse_error = 1;
}
break;
case OPT_KEY_VERSION: case OPT_ALGORITHM:
version = strtoul(optarg, &e, 0); algorithm = strtoul(optarg, &e, 0);
if (!*optarg || (e && *e)) { if (!*optarg || (e && *e)) {
VbExError("Invalid --version\n"); VbExError("Invalid --algorithm\n");
parse_error = 1; parse_error = 1;
} }
break; break;
case OPT_ALGORITHM: case OPT_MODE_PACK:
algorithm = strtoul(optarg, &e, 0); mode = i;
if (!*optarg || (e && *e)) { outfile = optarg;
VbExError("Invalid --algorithm\n"); break;
parse_error = 1;
}
break;
case OPT_MODE_PACK: case OPT_MODE_UNPACK:
mode = i; mode = i;
outfile = optarg; infile = optarg;
break; break;
case OPT_MODE_UNPACK: case OPT_COPYTO:
mode = i; outfile = optarg;
infile = optarg; break;
break; }
}
case OPT_COPYTO: if (parse_error)
outfile = optarg; return PrintHelp(progname);
break;
}
}
if (parse_error) switch (mode) {
return PrintHelp(progname); case OPT_MODE_PACK:
return Pack(infile, outfile, algorithm, version);
switch(mode) { case OPT_MODE_UNPACK:
case OPT_MODE_PACK: return Unpack(infile, outfile);
return Pack(infile, outfile, algorithm, version); default:
case OPT_MODE_UNPACK: printf("Must specify a mode.\n");
return Unpack(infile, outfile); return PrintHelp(progname);
default: }
printf("Must specify a mode.\n");
return PrintHelp(progname);
}
} }
DECLARE_FUTIL_COMMAND(vbutil_key, do_vbutil_key, DECLARE_FUTIL_COMMAND(vbutil_key, do_vbutil_key,

View File

@@ -17,312 +17,324 @@
#include "util_misc.h" #include "util_misc.h"
#include "vboot_common.h" #include "vboot_common.h"
/* Command line options */ /* Command line options */
enum { enum {
OPT_MODE_PACK = 1000, OPT_MODE_PACK = 1000,
OPT_MODE_UNPACK, OPT_MODE_UNPACK,
OPT_DATAPUBKEY, OPT_DATAPUBKEY,
OPT_SIGNPUBKEY, OPT_SIGNPUBKEY,
OPT_SIGNPRIVATE, OPT_SIGNPRIVATE,
OPT_SIGNPRIVATE_PEM, OPT_SIGNPRIVATE_PEM,
OPT_PEM_ALGORITHM, OPT_PEM_ALGORITHM,
OPT_EXTERNAL_SIGNER, OPT_EXTERNAL_SIGNER,
OPT_FLAGS, OPT_FLAGS,
}; };
static const struct option long_opts[] = { static const struct option long_opts[] = {
{"pack", 1, 0, OPT_MODE_PACK }, {"pack", 1, 0, OPT_MODE_PACK},
{"unpack", 1, 0, OPT_MODE_UNPACK }, {"unpack", 1, 0, OPT_MODE_UNPACK},
{"datapubkey", 1, 0, OPT_DATAPUBKEY }, {"datapubkey", 1, 0, OPT_DATAPUBKEY},
{"signpubkey", 1, 0, OPT_SIGNPUBKEY }, {"signpubkey", 1, 0, OPT_SIGNPUBKEY},
{"signprivate", 1, 0, OPT_SIGNPRIVATE }, {"signprivate", 1, 0, OPT_SIGNPRIVATE},
{"signprivate_pem", 1, 0, OPT_SIGNPRIVATE_PEM }, {"signprivate_pem", 1, 0, OPT_SIGNPRIVATE_PEM},
{"pem_algorithm", 1, 0, OPT_PEM_ALGORITHM }, {"pem_algorithm", 1, 0, OPT_PEM_ALGORITHM},
{"externalsigner", 1, 0, OPT_EXTERNAL_SIGNER }, {"externalsigner", 1, 0, OPT_EXTERNAL_SIGNER},
{"flags", 1, 0, OPT_FLAGS }, {"flags", 1, 0, OPT_FLAGS},
{NULL, 0, 0, 0} {NULL, 0, 0, 0}
}; };
static const char usage[] =
"Verified boot key block utility\n"
"\n"
"Usage: %s <--pack|--unpack> <file> [OPTIONS]\n"
"\n"
"For '--pack <file>', required OPTIONS are:\n"
" --datapubkey <file> Data public key in .vbpubk format\n"
"\n"
"Optional OPTIONS are:\n"
" --signprivate <file>"
" Signing private key in .vbprivk format.\n"
"OR\n"
" --signprivate_pem <file>\n"
" --pem_algorithm <algo>\n"
" Signing private key in .pem format and algorithm id.\n"
"(If one of the above arguments is not specified, the keyblock will\n"
"not be signed.)\n"
"\n"
" --flags <number> Specifies allowed use conditions.\n"
" --externalsigner \"cmd\""
" Use an external program cmd to calculate the signatures.\n"
"\n"
"For '--unpack <file>', optional OPTIONS are:\n"
" --signpubkey <file>"
" Signing public key in .vbpubk format. This is required to\n"
" verify a signed keyblock.\n"
" --datapubkey <file>"
" Write the data public key to this file.\n";
/* Print help and return error */ /* Print help and return error */
static int PrintHelp(char *progname) { static int PrintHelp(char *progname)
fprintf(stderr, {
"Verified boot key block utility\n" fprintf(stderr, usage, progname);
"\n" return 1;
"Usage: %s <--pack|--unpack> <file> [OPTIONS]\n"
"\n"
"For '--pack <file>', required OPTIONS are:\n"
" --datapubkey <file> Data public key in .vbpubk format\n"
"\n"
"Optional OPTIONS are:\n"
" --signprivate <file>"
" Signing private key in .vbprivk format.\n"
"OR\n"
" --signprivate_pem <file>\n"
" --pem_algorithm <algo>\n"
" Signing private key in .pem format and algorithm id.\n"
"(If one of the above arguments is not specified, the keyblock will\n"
"not be signed.)\n"
"\n"
" --flags <number> Specifies allowed use conditions.\n"
" --externalsigner \"cmd\""
" Use an external program cmd to calculate the signatures.\n"
"\n"
"For '--unpack <file>', optional OPTIONS are:\n"
" --signpubkey <file>"
" Signing public key in .vbpubk format. This is required to\n"
" verify a signed keyblock.\n"
" --datapubkey <file>"
" Write the data public key to this file.\n",
progname);
return 1;
} }
/* Pack a .keyblock */ /* Pack a .keyblock */
static int Pack(const char* outfile, const char* datapubkey, static int Pack(const char *outfile, const char *datapubkey,
const char* signprivate, const char *signprivate,
const char* signprivate_pem, uint64_t pem_algorithm, const char *signprivate_pem, uint64_t pem_algorithm,
uint64_t flags, uint64_t flags, const char *external_signer)
const char* external_signer) { {
VbPublicKey* data_key; VbPublicKey *data_key;
VbPrivateKey* signing_key = NULL; VbPrivateKey *signing_key = NULL;
VbKeyBlockHeader* block; VbKeyBlockHeader *block;
if (!outfile) { if (!outfile) {
fprintf(stderr, "vbutil_keyblock: Must specify output filename.\n"); fprintf(stderr,
return 1; "vbutil_keyblock: Must specify output filename.\n");
} return 1;
if (!datapubkey) { }
fprintf(stderr, "vbutil_keyblock: Must specify data public key.\n"); if (!datapubkey) {
return 1; fprintf(stderr,
} "vbutil_keyblock: Must specify data public key.\n");
return 1;
}
data_key = PublicKeyRead(datapubkey); data_key = PublicKeyRead(datapubkey);
if (!data_key) { if (!data_key) {
fprintf(stderr, "vbutil_keyblock: Error reading data key.\n"); fprintf(stderr, "vbutil_keyblock: Error reading data key.\n");
return 1; return 1;
} }
if (signprivate_pem) { if (signprivate_pem) {
if (pem_algorithm >= kNumAlgorithms) { if (pem_algorithm >= kNumAlgorithms) {
fprintf(stderr, "vbutil_keyblock: Invalid --pem_algorithm %" PRIu64 "\n", fprintf(stderr,
pem_algorithm); "vbutil_keyblock: Invalid --pem_algorithm %"
return 1; PRIu64 "\n", pem_algorithm);
} return 1;
if (external_signer) { }
/* External signing uses the PEM file directly. */ if (external_signer) {
block = KeyBlockCreate_external(data_key, /* External signing uses the PEM file directly. */
signprivate_pem, pem_algorithm, block = KeyBlockCreate_external(data_key,
flags, signprivate_pem,
external_signer); pem_algorithm, flags,
} else { external_signer);
signing_key = PrivateKeyReadPem(signprivate_pem, pem_algorithm); } else {
if (!signing_key) { signing_key =
fprintf(stderr, "vbutil_keyblock: Error reading signing key.\n"); PrivateKeyReadPem(signprivate_pem, pem_algorithm);
return 1; if (!signing_key) {
} fprintf(stderr, "vbutil_keyblock:"
block = KeyBlockCreate(data_key, signing_key, flags); " Error reading signing key.\n");
} return 1;
} else { }
if (signprivate) { block = KeyBlockCreate(data_key, signing_key, flags);
signing_key = PrivateKeyRead(signprivate); }
if (!signing_key) { } else {
fprintf(stderr, "vbutil_keyblock: Error reading signing key.\n"); if (signprivate) {
return 1; signing_key = PrivateKeyRead(signprivate);
} if (!signing_key) {
} fprintf(stderr, "vbutil_keyblock:"
block = KeyBlockCreate(data_key, signing_key, flags); " Error reading signing key.\n");
} return 1;
}
}
block = KeyBlockCreate(data_key, signing_key, flags);
}
free(data_key); free(data_key);
if (signing_key) if (signing_key)
free(signing_key); free(signing_key);
if (0 != KeyBlockWrite(outfile, block)) { if (0 != KeyBlockWrite(outfile, block)) {
fprintf(stderr, "vbutil_keyblock: Error writing key block.\n"); fprintf(stderr, "vbutil_keyblock: Error writing key block.\n");
return 1; return 1;
} }
free(block); free(block);
return 0; return 0;
} }
static int Unpack(const char* infile, const char* datapubkey, static int Unpack(const char *infile, const char *datapubkey,
const char* signpubkey) { const char *signpubkey)
VbPublicKey* data_key; {
VbPublicKey* sign_key = NULL; VbPublicKey *data_key;
VbKeyBlockHeader* block; VbPublicKey *sign_key = NULL;
VbKeyBlockHeader *block;
if (!infile) { if (!infile) {
fprintf(stderr, "vbutil_keyblock: Must specify filename\n"); fprintf(stderr, "vbutil_keyblock: Must specify filename\n");
return 1; return 1;
} }
block = KeyBlockRead(infile); block = KeyBlockRead(infile);
if (!block) { if (!block) {
fprintf(stderr, "vbutil_keyblock: Error reading key block.\n"); fprintf(stderr, "vbutil_keyblock: Error reading key block.\n");
return 1; return 1;
} }
/* If the block is signed, then verify it with the signing public key, since /* If the block is signed, then verify it with the signing public key,
KeyBlockRead() only verified the hash. */ * since KeyBlockRead() only verified the hash. */
if (block->key_block_signature.sig_size && signpubkey) { if (block->key_block_signature.sig_size && signpubkey) {
sign_key = PublicKeyRead(signpubkey); sign_key = PublicKeyRead(signpubkey);
if (!sign_key) { if (!sign_key) {
fprintf(stderr, "vbutil_keyblock: Error reading signpubkey.\n"); fprintf(stderr,
return 1; "vbutil_keyblock: Error reading signpubkey.\n");
} return 1;
if (0 != KeyBlockVerify(block, block->key_block_size, sign_key, 0)) { }
fprintf(stderr, "vbutil_keyblock: Error verifying key block.\n"); if (0 !=
return 1; KeyBlockVerify(block, block->key_block_size, sign_key, 0)) {
} fprintf(stderr, "vbutil_keyblock:"
free(sign_key); " Error verifying key block.\n");
} return 1;
}
free(sign_key);
}
printf("Key block file: %s\n", infile); printf("Key block file: %s\n", infile);
printf("Signature %s\n", sign_key ? "valid" : "ignored"); printf("Signature %s\n", sign_key ? "valid" : "ignored");
printf("Flags: %" PRIu64 " ", block->key_block_flags); printf("Flags: %" PRIu64 " ", block->key_block_flags);
if (block->key_block_flags & KEY_BLOCK_FLAG_DEVELOPER_0) if (block->key_block_flags & KEY_BLOCK_FLAG_DEVELOPER_0)
printf(" !DEV"); printf(" !DEV");
if (block->key_block_flags & KEY_BLOCK_FLAG_DEVELOPER_1) if (block->key_block_flags & KEY_BLOCK_FLAG_DEVELOPER_1)
printf(" DEV"); printf(" DEV");
if (block->key_block_flags & KEY_BLOCK_FLAG_RECOVERY_0) if (block->key_block_flags & KEY_BLOCK_FLAG_RECOVERY_0)
printf(" !REC"); printf(" !REC");
if (block->key_block_flags & KEY_BLOCK_FLAG_RECOVERY_1) if (block->key_block_flags & KEY_BLOCK_FLAG_RECOVERY_1)
printf(" REC"); printf(" REC");
printf("\n"); printf("\n");
data_key = &block->data_key; data_key = &block->data_key;
printf("Data key algorithm: %" PRIu64 " %s\n", data_key->algorithm, printf("Data key algorithm: %" PRIu64 " %s\n", data_key->algorithm,
(data_key->algorithm < kNumAlgorithms ? (data_key->algorithm < kNumAlgorithms ?
algo_strings[data_key->algorithm] : "(invalid)")); algo_strings[data_key->algorithm] : "(invalid)"));
printf("Data key version: %" PRIu64 "\n", data_key->key_version); printf("Data key version: %" PRIu64 "\n", data_key->key_version);
printf("Data key sha1sum: "); printf("Data key sha1sum: ");
PrintPubKeySha1Sum(data_key); PrintPubKeySha1Sum(data_key);
printf("\n"); printf("\n");
if (datapubkey) { if (datapubkey) {
if (0 != PublicKeyWrite(datapubkey, data_key)) { if (0 != PublicKeyWrite(datapubkey, data_key)) {
fprintf(stderr, fprintf(stderr, "vbutil_keyblock:"
"vbutil_keyblock: unable to write public key\n"); " unable to write public key\n");
return 1; return 1;
} }
} }
free(block); free(block);
return 0; return 0;
} }
static int do_vbutil_keyblock(int argc, char *argv[])
{
static int do_vbutil_keyblock(int argc, char* argv[]) { char *filename = NULL;
char *datapubkey = NULL;
char *signpubkey = NULL;
char *signprivate = NULL;
char *signprivate_pem = NULL;
char *external_signer = NULL;
uint64_t flags = 0;
uint64_t pem_algorithm = 0;
int is_pem_algorithm = 0;
int mode = 0;
int parse_error = 0;
char *e;
int i;
char* filename = NULL; char *progname = strrchr(argv[0], '/');
char* datapubkey = NULL; if (progname)
char* signpubkey = NULL; progname++;
char* signprivate = NULL; else
char* signprivate_pem = NULL; progname = argv[0];
char* external_signer = NULL;
uint64_t flags = 0;
uint64_t pem_algorithm = 0;
int is_pem_algorithm = 0;
int mode = 0;
int parse_error = 0;
char* e;
int i;
char *progname = strrchr(argv[0], '/'); while ((i = getopt_long(argc, argv, "", long_opts, NULL)) != -1) {
if (progname) switch (i) {
progname++; case '?':
else /* Unhandled option */
progname = argv[0]; printf("Unknown option\n");
parse_error = 1;
break;
while ((i = getopt_long(argc, argv, "", long_opts, NULL)) != -1) { case OPT_MODE_PACK:
switch (i) { case OPT_MODE_UNPACK:
case '?': mode = i;
/* Unhandled option */ filename = optarg;
printf("Unknown option\n"); break;
parse_error = 1;
break;
case OPT_MODE_PACK: case OPT_DATAPUBKEY:
case OPT_MODE_UNPACK: datapubkey = optarg;
mode = i; break;
filename = optarg;
break;
case OPT_DATAPUBKEY: case OPT_SIGNPUBKEY:
datapubkey = optarg; signpubkey = optarg;
break; break;
case OPT_SIGNPUBKEY: case OPT_SIGNPRIVATE:
signpubkey = optarg; signprivate = optarg;
break; break;
case OPT_SIGNPRIVATE: case OPT_SIGNPRIVATE_PEM:
signprivate = optarg; signprivate_pem = optarg;
break; break;
case OPT_SIGNPRIVATE_PEM: case OPT_PEM_ALGORITHM:
signprivate_pem = optarg; pem_algorithm = strtoul(optarg, &e, 0);
break; if (!*optarg || (e && *e)) {
fprintf(stderr, "Invalid --pem_algorithm\n");
parse_error = 1;
} else {
is_pem_algorithm = 1;
}
break;
case OPT_PEM_ALGORITHM: case OPT_EXTERNAL_SIGNER:
pem_algorithm = strtoul(optarg, &e, 0); external_signer = optarg;
if (!*optarg || (e && *e)) { break;
fprintf(stderr, "Invalid --pem_algorithm\n");
parse_error = 1;
} else {
is_pem_algorithm = 1;
}
break;
case OPT_EXTERNAL_SIGNER: case OPT_FLAGS:
external_signer = optarg; flags = strtoul(optarg, &e, 0);
break; if (!*optarg || (e && *e)) {
fprintf(stderr, "Invalid --flags\n");
parse_error = 1;
}
break;
}
}
case OPT_FLAGS: /* Check if the right combination of options was provided. */
flags = strtoul(optarg, &e, 0); if (signprivate && signprivate_pem) {
if (!*optarg || (e && *e)) { fprintf(stderr,
fprintf(stderr, "Invalid --flags\n"); "Only one of --signprivate or --signprivate_pem must"
parse_error = 1; " be specified\n");
} parse_error = 1;
break; }
}
}
/* Check if the right combination of options was provided. */ if (signprivate_pem && !is_pem_algorithm) {
if (signprivate && signprivate_pem) { fprintf(stderr, "--pem_algorithm must be used with"
fprintf(stderr, "Only one of --signprivate or --signprivate_pem must" " --signprivate_pem\n");
" be specified\n"); parse_error = 1;
parse_error = 1; }
}
if (signprivate_pem && !is_pem_algorithm) { if (external_signer && !signprivate_pem) {
fprintf(stderr, "--pem_algorithm must be used with --signprivate_pem\n"); fprintf(stderr,
parse_error = 1; "--externalsigner must be used with --signprivate_pem"
} "\n");
parse_error = 1;
}
if (external_signer && !signprivate_pem) { if (parse_error)
fprintf(stderr, "--externalsigner must be used with --signprivate_pem" return PrintHelp(progname);
"\n");
parse_error = 1;
}
if (parse_error) switch (mode) {
return PrintHelp(progname); case OPT_MODE_PACK:
return Pack(filename, datapubkey, signprivate,
switch(mode) { signprivate_pem, pem_algorithm,
case OPT_MODE_PACK: flags, external_signer);
return Pack(filename, datapubkey, signprivate, case OPT_MODE_UNPACK:
signprivate_pem, pem_algorithm, return Unpack(filename, datapubkey, signpubkey);
flags, default:
external_signer); printf("Must specify a mode.\n");
case OPT_MODE_UNPACK: return PrintHelp(progname);
return Unpack(filename, datapubkey, signpubkey); }
default:
printf("Must specify a mode.\n");
return PrintHelp(progname);
}
} }
DECLARE_FUTIL_COMMAND(vbutil_keyblock, do_vbutil_keyblock, DECLARE_FUTIL_COMMAND(vbutil_keyblock, do_vbutil_keyblock,

View File

@@ -14,106 +14,109 @@
#include "vboot_api.h" #include "vboot_api.h"
#include "vboot_host.h" #include "vboot_host.h"
static uint8_t* GetKernelConfig(uint8_t* blob, size_t blob_size, static uint8_t *GetKernelConfig(uint8_t * blob, size_t blob_size,
uint64_t kernel_body_load_address) { uint64_t kernel_body_load_address)
{
VbKeyBlockHeader* key_block; VbKeyBlockHeader *key_block;
VbKernelPreambleHeader* preamble; VbKernelPreambleHeader *preamble;
uint32_t now = 0; uint32_t now = 0;
uint32_t offset = 0; uint32_t offset = 0;
/* Skip the key block */ /* Skip the key block */
key_block = (VbKeyBlockHeader*)blob; key_block = (VbKeyBlockHeader *) blob;
now += key_block->key_block_size; now += key_block->key_block_size;
if (now + blob > blob + blob_size) { if (now + blob > blob + blob_size) {
VbExError("key_block_size advances past the end of the blob\n"); VbExError("key_block_size advances past the end of the blob\n");
return NULL; return NULL;
} }
/* Open up the preamble */ /* Open up the preamble */
preamble = (VbKernelPreambleHeader*)(blob + now); preamble = (VbKernelPreambleHeader *) (blob + now);
now += preamble->preamble_size; now += preamble->preamble_size;
if (now + blob > blob + blob_size) { if (now + blob > blob + blob_size) {
VbExError("preamble_size advances past the end of the blob\n"); VbExError("preamble_size advances past the end of the blob\n");
return NULL; return NULL;
} }
/* Read body_load_address from preamble if no kernel_body_load_address */ /* Read body_load_address from preamble if no
if (kernel_body_load_address == USE_PREAMBLE_LOAD_ADDR) * kernel_body_load_address */
kernel_body_load_address = preamble->body_load_address; if (kernel_body_load_address == USE_PREAMBLE_LOAD_ADDR)
kernel_body_load_address = preamble->body_load_address;
/* The x86 kernels have a pointer to the kernel commandline in the zeropage /* The x86 kernels have a pointer to the kernel commandline in the
* table, but that's irrelevant for ARM. Both types keep the config blob in * zeropage table, but that's irrelevant for ARM. Both types keep the
* the same place, so just go find it. */ * config blob in the same place, so just go find it. */
offset = preamble->bootloader_address - offset = preamble->bootloader_address -
(kernel_body_load_address + CROS_PARAMS_SIZE + (kernel_body_load_address + CROS_PARAMS_SIZE +
CROS_CONFIG_SIZE) + now; CROS_CONFIG_SIZE) + now;
if (offset > blob_size) { if (offset > blob_size) {
VbExError("params are outside of the memory blob: %x\n", offset); VbExError("params are outside of the memory blob: %x\n",
return NULL; offset);
} return NULL;
return blob + offset; }
return blob + offset;
} }
static void* MMapFile(const char* filename, size_t *size) { static void *MMapFile(const char *filename, size_t * size)
FILE* f; {
uint8_t* buf; FILE *f;
long file_size = 0; uint8_t *buf;
long file_size = 0;
f = fopen(filename, "rb"); f = fopen(filename, "rb");
if (!f) { if (!f) {
VBDEBUG(("Unable to open file %s\n", filename)); VBDEBUG(("Unable to open file %s\n", filename));
return NULL; return NULL;
} }
fseek(f, 0, SEEK_END); fseek(f, 0, SEEK_END);
file_size = ftell(f); file_size = ftell(f);
rewind(f); rewind(f);
if (file_size <= 0) { if (file_size <= 0) {
fclose(f); fclose(f);
return NULL; return NULL;
} }
*size = (size_t) file_size; *size = (size_t) file_size;
/* Uses a host primitive as this is not meant for firmware use. */ /* Uses a host primitive as this is not meant for firmware use. */
buf = mmap(NULL, *size, PROT_READ, MAP_PRIVATE, fileno(f), 0); buf = mmap(NULL, *size, PROT_READ, MAP_PRIVATE, fileno(f), 0);
if (buf == MAP_FAILED) { if (buf == MAP_FAILED) {
VbExError("Failed to mmap the file %s\n", filename); VbExError("Failed to mmap the file %s\n", filename);
fclose(f); fclose(f);
return NULL; return NULL;
} }
fclose(f); fclose(f);
return buf; return buf;
} }
char *FindKernelConfig(const char *infile, uint64_t kernel_body_load_address) char *FindKernelConfig(const char *infile, uint64_t kernel_body_load_address)
{ {
uint8_t* blob; uint8_t *blob;
size_t blob_size; size_t blob_size;
uint8_t *config = NULL; uint8_t *config = NULL;
char *newstr = NULL; char *newstr = NULL;
blob = MMapFile(infile, &blob_size); blob = MMapFile(infile, &blob_size);
if (!blob) { if (!blob) {
VbExError("Error reading input file\n"); VbExError("Error reading input file\n");
return 0; return 0;
} }
config = GetKernelConfig(blob, blob_size, kernel_body_load_address); config = GetKernelConfig(blob, blob_size, kernel_body_load_address);
if (!config) { if (!config) {
VbExError("Error parsing input file\n"); VbExError("Error parsing input file\n");
munmap(blob, blob_size); munmap(blob, blob_size);
return 0; return 0;
} }
newstr = strndup((char *)config, CROS_CONFIG_SIZE); newstr = strndup((char *)config, CROS_CONFIG_SIZE);
if (!newstr) if (!newstr)
VbExError("Can't allocate new string\n"); VbExError("Can't allocate new string\n");
munmap(blob, blob_size); munmap(blob, blob_size);
return newstr; return newstr;
} }

View File

@@ -28,7 +28,7 @@
/******************************************************************************/ /******************************************************************************/
static const char * const usage= "\n\ static const char *const usage = "\n\
Usage: " MYNAME " PROGRAM|COMMAND [args...]\n\ Usage: " MYNAME " PROGRAM|COMMAND [args...]\n\
\n\ \n\
This is the unified firmware utility, which will eventually replace\n\ This is the unified firmware utility, which will eventually replace\n\
@@ -45,25 +45,26 @@ In either case it will append some usage information to " LOGFILE "\n\
static int do_help(int argc, char *argv[]) static int do_help(int argc, char *argv[])
{ {
const struct futil_cmd_t * const *cmd; const struct futil_cmd_t *const *cmd;
int i; int i;
fputs(usage, stdout); fputs(usage, stdout);
printf("The following commands are built-in:\n\n"); printf("The following commands are built-in:\n\n");
for (cmd = futil_cmds; *cmd; cmd++) for (cmd = futil_cmds; *cmd; cmd++)
printf(" %-20s %s\n", (*cmd)->name, (*cmd)->shorthelp); printf(" %-20s %s\n", (*cmd)->name, (*cmd)->shorthelp);
printf("\n"); printf("\n");
if (argc) { if (argc) {
printf("FYI, you added these args that I'm ignoring:\n"); printf("FYI, you added these args that I'm ignoring:\n");
for (i = 0; i < argc; i++) for (i = 0; i < argc; i++)
printf("argv[%d] = %s\n", i, argv[i]); printf("argv[%d] = %s\n", i, argv[i]);
} }
return 0; return 0;
} }
DECLARE_FUTIL_COMMAND(help, do_help, DECLARE_FUTIL_COMMAND(help, do_help,
"Show a bit of help (you're looking at it)"); "Show a bit of help (you're looking at it)");
@@ -71,11 +72,11 @@ DECLARE_FUTIL_COMMAND(help, do_help,
* These are built-in functions that we'd like to abandon completely someday. * These are built-in functions that we'd like to abandon completely someday.
* TODO: If no one complains, get rid of them. * TODO: If no one complains, get rid of them.
*/ */
static const char * const dep_cmds[] = { static const char *const dep_cmds[] = {
"dev_sign_file", "dev_sign_file",
}; };
static const char * const dep_usage= "\n\ static const char *const dep_usage = "\n\
The program \"%s\" is deprecated and may go away soon.\n\ The program \"%s\" is deprecated and may go away soon.\n\
\n\ \n\
If you feel this is in error, please open a bug at\n\ If you feel this is in error, please open a bug at\n\
@@ -89,8 +90,8 @@ In the meantime, you may continue to use the program by invoking it as\n\
static void deprecated(const char *depname) static void deprecated(const char *depname)
{ {
fprintf(stderr, dep_usage, depname, depname); fprintf(stderr, dep_usage, depname, depname);
exit(1); exit(1);
} }
/******************************************************************************/ /******************************************************************************/
@@ -101,188 +102,187 @@ static int log_fd = -1;
/* Write the string and a newline. Silently give up on errors */ /* Write the string and a newline. Silently give up on errors */
static void log_str(char *str) static void log_str(char *str)
{ {
int len, done, n; int len, done, n;
if (log_fd < 0) if (log_fd < 0)
return; return;
if (!str) if (!str)
str = "(NULL)"; str = "(NULL)";
len = strlen(str); len = strlen(str);
if (len == 0) { if (len == 0) {
str = "(EMPTY)"; str = "(EMPTY)";
len = strlen(str); len = strlen(str);
} }
for (done = 0; done < len; done += n) { for (done = 0; done < len; done += n) {
n = write(log_fd, str + done, len - done); n = write(log_fd, str + done, len - done);
if (n < 0) if (n < 0)
return; return;
} }
if (write(log_fd, "\n", 1) < 0) if (write(log_fd, "\n", 1) < 0)
return; return;
} }
static void log_close(void) static void log_close(void)
{ {
struct flock lock; struct flock lock;
if (log_fd >= 0) { if (log_fd >= 0) {
memset(&lock, 0, sizeof(lock)); memset(&lock, 0, sizeof(lock));
lock.l_type = F_UNLCK; lock.l_type = F_UNLCK;
lock.l_whence = SEEK_SET; lock.l_whence = SEEK_SET;
if (fcntl(log_fd, F_SETLKW, &lock)) if (fcntl(log_fd, F_SETLKW, &lock))
perror("Unable to unlock log file"); perror("Unable to unlock log file");
close(log_fd); close(log_fd);
log_fd = -1; log_fd = -1;
} }
} }
static void log_open(void) static void log_open(void)
{ {
struct flock lock; struct flock lock;
int ret; int ret;
#ifdef FORCE_LOGGING_ON #ifdef FORCE_LOGGING_ON
log_fd = open(LOGFILE, O_WRONLY|O_APPEND|O_CREAT, 0666); log_fd = open(LOGFILE, O_WRONLY | O_APPEND | O_CREAT, 0666);
#else #else
log_fd = open(LOGFILE, O_WRONLY|O_APPEND); log_fd = open(LOGFILE, O_WRONLY | O_APPEND);
#endif #endif
if (log_fd < 0) { if (log_fd < 0) {
if (errno != EACCES) if (errno != EACCES)
return; return;
/* Permission problems should improve shortly ... */ /* Permission problems should improve shortly ... */
sleep(1); sleep(1);
log_fd = open(LOGFILE, O_WRONLY|O_APPEND|O_CREAT, 0666); log_fd = open(LOGFILE, O_WRONLY | O_APPEND | O_CREAT, 0666);
if (log_fd < 0) /* Nope, they didn't */ if (log_fd < 0) /* Nope, they didn't */
return; return;
} }
/* Let anyone have a turn */ /* Let anyone have a turn */
fchmod(log_fd, 0666); fchmod(log_fd, 0666);
/* But only one at a time */ /* But only one at a time */
memset(&lock, 0, sizeof(lock)); memset(&lock, 0, sizeof(lock));
lock.l_type = F_WRLCK; lock.l_type = F_WRLCK;
lock.l_whence = SEEK_END; lock.l_whence = SEEK_END;
ret = fcntl(log_fd, F_SETLKW, &lock); /* this blocks */ ret = fcntl(log_fd, F_SETLKW, &lock); /* this blocks */
if (ret < 0) if (ret < 0)
log_close(); log_close();
} }
#define CALLER_PREFIX "CALLER:" #define CALLER_PREFIX "CALLER:"
static void log_args(int argc, char *argv[]) static void log_args(int argc, char *argv[])
{ {
int i; int i;
ssize_t r; ssize_t r;
pid_t parent; pid_t parent;
char buf[80]; char buf[80];
char str_caller[PATH_MAX + sizeof(CALLER_PREFIX)] = CALLER_PREFIX; char str_caller[PATH_MAX + sizeof(CALLER_PREFIX)] = CALLER_PREFIX;
char *truename = str_caller + sizeof(CALLER_PREFIX) - 1; char *truename = str_caller + sizeof(CALLER_PREFIX) - 1;
/* Note: truename starts on the \0 from CALLER_PREFIX, so we can write /* Note: truename starts on the \0 from CALLER_PREFIX, so we can write
* PATH_MAX chars into truename and still append a \0 at the end. */ * PATH_MAX chars into truename and still append a \0 at the end. */
log_open(); log_open();
/* delimiter */ /* delimiter */
log_str("##### HEY #####"); log_str("##### HEY #####");
/* Can we tell who called us? */ /* Can we tell who called us? */
parent = getppid(); parent = getppid();
snprintf(buf, sizeof(buf), "/proc/%d/exe", parent); snprintf(buf, sizeof(buf), "/proc/%d/exe", parent);
r = readlink(buf, truename, PATH_MAX); r = readlink(buf, truename, PATH_MAX);
if (r >= 0) { if (r >= 0) {
truename[r] = '\0'; truename[r] = '\0';
log_str(str_caller); log_str(str_caller);
} }
/* Now log the stuff about ourselves */ /* Now log the stuff about ourselves */
for (i = 0; i < argc; i++) for (i = 0; i < argc; i++)
log_str(argv[i]); log_str(argv[i]);
log_close(); log_close();
} }
/******************************************************************************/ /******************************************************************************/
/* Here we go */ /* Here we go */
int main(int argc, char *argv[], char *envp[]) int main(int argc, char *argv[], char *envp[])
{ {
char *fullname, *progname; char *fullname, *progname;
char truename[PATH_MAX]; char truename[PATH_MAX];
char buf[80]; char buf[80];
pid_t myproc; pid_t myproc;
ssize_t r; ssize_t r;
const struct futil_cmd_t * const *cmd; const struct futil_cmd_t *const *cmd;
int i; int i;
int via_symlink = 0; int via_symlink = 0;
log_args(argc, argv); log_args(argc, argv);
/* How were we invoked? */ /* How were we invoked? */
fullname = strdup(argv[0]); fullname = strdup(argv[0]);
progname = strrchr(argv[0], '/'); progname = strrchr(argv[0], '/');
if (progname) if (progname)
progname++; progname++;
else else
progname = argv[0]; progname = argv[0];
/* Invoked directly by name */ /* Invoked directly by name */
if (0 == strcmp(progname, MYNAME) || 0 == strcmp(progname, MYNAME_S)) { if (0 == strcmp(progname, MYNAME) || 0 == strcmp(progname, MYNAME_S)) {
if (argc < 2) { /* must have an argument */ if (argc < 2) { /* must have an argument */
do_help(0, 0); do_help(0, 0);
exit(1); exit(1);
} }
/* We can just pass the rest along, then */ /* We can just pass the rest along, then */
argc--; argc--;
argv++; argv++;
/* So now what function do we want to invoke? */ /* So now what function do we want to invoke? */
progname = strrchr(argv[0], '/'); progname = strrchr(argv[0], '/');
if (progname) if (progname)
progname++; progname++;
else else
progname = argv[0]; progname = argv[0];
} else { /* Invoked by symlink */ } else { /* Invoked by symlink */
via_symlink = 1; via_symlink = 1;
/* Block any deprecated functions. */ /* Block any deprecated functions. */
for (i = 0; i < ARRAY_SIZE(dep_cmds); i++) for (i = 0; i < ARRAY_SIZE(dep_cmds); i++)
if (0 == strcmp(dep_cmds[i], progname)) if (0 == strcmp(dep_cmds[i], progname))
deprecated(progname); deprecated(progname);
} }
/* See if it's asking for something we know how to do ourselves */ /* See if it's asking for something we know how to do ourselves */
for (cmd = futil_cmds; *cmd; cmd++) for (cmd = futil_cmds; *cmd; cmd++)
if (0 == strcmp((*cmd)->name, progname)) if (0 == strcmp((*cmd)->name, progname))
return (*cmd)->handler(argc, argv); return (*cmd)->handler(argc, argv);
/* Nope */ /* Nope */
if (!via_symlink) { if (!via_symlink) {
do_help(0, 0); do_help(0, 0);
exit(1); exit(1);
} }
/* Complain about bogus symlink */ /* Complain about bogus symlink */
myproc = getpid(); myproc = getpid();
snprintf(buf, sizeof(buf), "/proc/%d/exe", myproc); snprintf(buf, sizeof(buf), "/proc/%d/exe", myproc);
r = readlink(buf, truename, PATH_MAX - 1); r = readlink(buf, truename, PATH_MAX - 1);
if (r < 0) { if (r < 0) {
fprintf(stderr, "%s is lost: %s => %s: %s\n", MYNAME, argv[0], fprintf(stderr, "%s is lost: %s => %s: %s\n", MYNAME, argv[0],
buf, strerror(errno)); buf, strerror(errno));
exit(1); exit(1);
} }
truename[r] = '\0'; truename[r] = '\0';
fprintf(stderr, "\n\ fprintf(stderr, "\n\
The program\n\n %s\n\nis a symlink to\n\n %s\n\ The program\n\n %s\n\nis a symlink to\n\n %s\n\
\n\ \n\
However, " MYNAME " doesn't know how to implement that function.\n\ However, " MYNAME " doesn't know how to implement that function.\n\
@@ -292,5 +292,5 @@ after a fresh checkout/build/install, please open a bug at\n\
\n\ \n\
http://dev.chromium.org/for-testers/bug-reporting-guidelines\n\ http://dev.chromium.org/for-testers/bug-reporting-guidelines\n\
\n", fullname, truename); \n", fullname, truename);
return 1; return 1;
} }

View File

@@ -10,9 +10,9 @@
/* Here's a structure to define the commands that futility implements. */ /* Here's a structure to define the commands that futility implements. */
struct futil_cmd_t { struct futil_cmd_t {
const char * const name; const char *const name;
int (*const handler)(int argc, char **argv); int (*const handler) (int argc, char **argv);
const char * const shorthelp; const char *const shorthelp;
}; };
/* /*
@@ -33,7 +33,7 @@ struct futil_cmd_t {
= &__cmd_##NAME = &__cmd_##NAME
/* This is the list of pointers to all commands. */ /* This is the list of pointers to all commands. */
extern const struct futil_cmd_t * const futil_cmds[]; extern const struct futil_cmd_t *const futil_cmds[];
/* Size of an array */ /* Size of an array */
#ifndef ARRAY_SIZE #ifndef ARRAY_SIZE

View File

@@ -1,65 +1,62 @@
// Copyright 2010 The Chromium OS Authors. All rights reserved. /* Copyright 2010 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be * Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. * found in the LICENSE file.
// *
// Constants describing the kernel blob content. * Constants describing the kernel blob content.
*/
#ifndef VBOOT_REFERENCE_KERNEL_BLOB_H_ #ifndef VBOOT_REFERENCE_KERNEL_BLOB_H_
#define VBOOT_REFERENCE_KERNEL_BLOB_H_ #define VBOOT_REFERENCE_KERNEL_BLOB_H_
/* Maximum kernel command-line size */
// Maximum kernel command-line size
#define CROS_CONFIG_SIZE 4096 #define CROS_CONFIG_SIZE 4096
// Size of the x86 zeropage table /* Size of the x86 zeropage table */
#define CROS_PARAMS_SIZE 4096 #define CROS_PARAMS_SIZE 4096
// Alignment of various chunks within the kernel blob /* Alignment of various chunks within the kernel blob */
#define CROS_ALIGN 4096 #define CROS_ALIGN 4096
// Sentinel RAM address indicating that no entry address is specified /* Sentinel RAM address indicating that no entry address is specified */
#define CROS_NO_ENTRY_ADDR (~0) #define CROS_NO_ENTRY_ADDR (~0)
// RAM address where the 32-bit kernel expects to be started /* RAM address where the 32-bit kernel expects to be started */
#define CROS_32BIT_ENTRY_ADDR 0x100000 #define CROS_32BIT_ENTRY_ADDR 0x100000
// Simplified version of x86 kernel e820 memory map entries /* Simplified version of x86 kernel e820 memory map entries */
#define E820_ENTRY_MAX 128 #define E820_ENTRY_MAX 128
#define E820_TYPE_RAM 1 #define E820_TYPE_RAM 1
#define E820_TYPE_RESERVED 2 #define E820_TYPE_RESERVED 2
struct linux_kernel_e820entry { struct linux_kernel_e820entry {
uint64_t start_addr; uint64_t start_addr;
uint64_t segment_size; uint64_t segment_size;
uint32_t segment_type; uint32_t segment_type;
} __attribute__((packed));
// Simplified version of the x86 kernel zeropage table
struct linux_kernel_params
{
uint8_t pad0[0x1e8 - 0x0];
uint8_t n_e820_entry; // 1e8
uint8_t pad1[0x1f1 - 0x1e9];
uint8_t setup_sects; // 1f1
uint8_t pad2[0x1fe - 0x1f2];
uint16_t boot_flag; // 1fe
uint16_t jump; // 200
uint32_t header; // 202
uint16_t version; // 206
uint8_t pad3[0x210 - 0x208];
uint8_t type_of_loader; // 210
uint8_t pad4[0x218 - 0x211];
uint32_t ramdisk_image; // 218
uint32_t ramdisk_size; // 21c
uint8_t pad5[0x228 - 0x220];
uint32_t cmd_line_ptr; // 228
uint32_t ramdisk_max; // 22c
uint32_t kernel_alignment; // 230
uint8_t relocatable_kernel; // 234
uint8_t min_alignment; // 235
uint8_t pad6[0x2d0 - 0x236];
struct linux_kernel_e820entry e820_entries[E820_ENTRY_MAX]; // 2d0 - cd0
} __attribute__ ((packed)); } __attribute__ ((packed));
/* Simplified version of the x86 kernel zeropage table */
struct linux_kernel_params {
uint8_t pad0[0x1e8 - 0x0];
uint8_t n_e820_entry; /* 1e8 */
uint8_t pad1[0x1f1 - 0x1e9];
uint8_t setup_sects; /* 1f1 */
uint8_t pad2[0x1fe - 0x1f2];
uint16_t boot_flag; /* 1fe */
uint16_t jump; /* 200 */
uint32_t header; /* 202 */
uint16_t version; /* 206 */
uint8_t pad3[0x210 - 0x208];
uint8_t type_of_loader; /* 210 */
uint8_t pad4[0x218 - 0x211];
uint32_t ramdisk_image; /* 218 */
uint32_t ramdisk_size; /* 21c */
uint8_t pad5[0x228 - 0x220];
uint32_t cmd_line_ptr; /* 228 */
uint32_t ramdisk_max; /* 22c */
uint32_t kernel_alignment; /* 230 */
uint8_t relocatable_kernel; /* 234 */
uint8_t min_alignment; /* 235 */
uint8_t pad6[0x2d0 - 0x236];
struct linux_kernel_e820entry e820_entries[E820_ENTRY_MAX]; /* 2d0-cd0 */
} __attribute__ ((packed));
#endif // VBOOT_REFERENCE_KERNEL_BLOB_H_ #endif /* VBOOT_REFERENCE_KERNEL_BLOB_H_ */