blob: 7d5b7c137a66bbce30c0679ad30fec255f185469 [file] [log] [blame]
/* Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
* Verified boot key block utility
*/
#include <getopt.h>
#include <inttypes.h> /* For PRIu64 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "cryptolib.h"
#include "host_common.h"
#include "vboot_common.h"
/* Command line options */
enum {
OPT_MODE_PACK = 1000,
OPT_MODE_UNPACK,
OPT_DATAPUBKEY,
OPT_SIGNPUBKEY,
OPT_SIGNPRIVATE,
OPT_FLAGS,
};
static struct option long_opts[] = {
{"pack", 1, 0, OPT_MODE_PACK },
{"unpack", 1, 0, OPT_MODE_UNPACK },
{"datapubkey", 1, 0, OPT_DATAPUBKEY },
{"signpubkey", 1, 0, OPT_SIGNPUBKEY },
{"signprivate", 1, 0, OPT_SIGNPRIVATE },
{"flags", 1, 0, OPT_FLAGS },
{NULL, 0, 0, 0}
};
/* Print help and return error */
static int PrintHelp(char *progname) {
fprintf(stderr,
"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. Without this arg,\n"
" the keyblock will not be signed.\n"
" --flags <number> Specifies allowed use conditions.\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 */
static int Pack(const char* outfile, const char* datapubkey,
const char* signprivate, uint64_t flags) {
VbPublicKey* data_key;
VbPrivateKey* signing_key = NULL;
VbKeyBlockHeader* block;
if (!outfile) {
fprintf(stderr, "vbutil_keyblock: Must specify output filename.\n");
return 1;
}
if (!datapubkey) {
fprintf(stderr, "vbutil_keyblock: Must specify data public key.\n");
return 1;
}
data_key = PublicKeyRead(datapubkey);
if (!data_key) {
fprintf(stderr, "vbutil_keyblock: Error reading data key.\n");
return 1;
}
if (signprivate) {
signing_key = PrivateKeyRead(signprivate);
if (!signing_key) {
fprintf(stderr, "vbutil_keyblock: Error reading signing key.\n");
return 1;
}
}
block = KeyBlockCreate(data_key, signing_key, flags);
Free(data_key);
if (signing_key)
Free(signing_key);
if (0 != KeyBlockWrite(outfile, block)) {
fprintf(stderr, "vbutil_keyblock: Error writing key block.\n");
return 1;
}
Free(block);
return 0;
}
static int Unpack(const char* infile, const char* datapubkey,
const char* signpubkey) {
VbPublicKey* data_key;
VbPublicKey* sign_key = NULL;
VbKeyBlockHeader* block;
if (!infile) {
fprintf(stderr, "vbutil_keyblock: Must specify filename\n");
return 1;
}
block = KeyBlockRead(infile);
if (!block) {
fprintf(stderr, "vbutil_keyblock: Error reading key block.\n");
return 1;
}
/* If the block is signed, then verify it with the signing public key, since
KeyBlockRead() only verified the hash. */
if (block->key_block_signature.sig_size) {
if (!signpubkey) {
fprintf(stderr,
"vbutil_keyblock: keyblock requires public key to verify\n");
return 1;
}
sign_key = PublicKeyRead(signpubkey);
if (!sign_key) {
fprintf(stderr, "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");
return 1;
}
printf("Signature algorithm: %" PRIu64 " %s\n", sign_key->algorithm,
(sign_key->algorithm < kNumAlgorithms ?
algo_strings[sign_key->algorithm] : "(invalid)"));
Free(sign_key);
} else {
printf("Signature Algorithm: <none>\n");
}
printf("Key block file: %s\n", infile);
printf("Flags: %" PRIu64 "\n", block->key_block_flags);
data_key = &block->data_key;
printf("Data key algorithm: %" PRIu64 " %s\n", data_key->algorithm,
(data_key->algorithm < kNumAlgorithms ?
algo_strings[data_key->algorithm] : "(invalid)"));
printf("Data key version: %" PRIu64 "\n", data_key->key_version);
if (datapubkey) {
if (0 != PublicKeyWrite(datapubkey, data_key)) {
fprintf(stderr,
"vbutil_keyblock: unable to write public key\n");
return 1;
}
}
Free(block);
return 0;
}
int main(int argc, char* argv[]) {
char* filename = NULL;
char* datapubkey = NULL;
char* signpubkey = NULL;
char* signprivate = NULL;
uint64_t flags = 0;
int mode = 0;
int parse_error = 0;
char* e;
int i;
char *progname = strrchr(argv[0], '/');
if (progname)
progname++;
else
progname = argv[0];
while ((i = getopt_long(argc, argv, "", long_opts, NULL)) != -1) {
switch (i) {
case '?':
/* Unhandled option */
printf("Unknown option\n");
parse_error = 1;
break;
case OPT_MODE_PACK:
case OPT_MODE_UNPACK:
mode = i;
filename = optarg;
break;
case OPT_DATAPUBKEY:
datapubkey = optarg;
break;
case OPT_SIGNPUBKEY:
signpubkey = optarg;
break;
case OPT_SIGNPRIVATE:
signprivate = optarg;
break;
case OPT_FLAGS:
flags = strtoul(optarg, &e, 0);
if (!*optarg || (e && *e)) {
printf("Invalid --flags\n");
parse_error = 1;
}
break;
}
}
if (parse_error)
return PrintHelp(progname);
switch(mode) {
case OPT_MODE_PACK:
return Pack(filename, datapubkey, signprivate, flags);
case OPT_MODE_UNPACK:
return Unpack(filename, datapubkey, signpubkey);
default:
printf("Must specify a mode.\n");
return PrintHelp(progname);
}
}