diff options
Diffstat (limited to 'futility/cmd_vbutil_keyblock.c')
-rw-r--r-- | futility/cmd_vbutil_keyblock.c | 329 |
1 files changed, 329 insertions, 0 deletions
diff --git a/futility/cmd_vbutil_keyblock.c b/futility/cmd_vbutil_keyblock.c new file mode 100644 index 00000000..d15afd89 --- /dev/null +++ b/futility/cmd_vbutil_keyblock.c @@ -0,0 +1,329 @@ +/* Copyright (c) 2011 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 <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "cryptolib.h" +#include "futility.h" +#include "host_common.h" +#include "util_misc.h" +#include "vboot_common.h" + + +/* Command line options */ +enum { + OPT_MODE_PACK = 1000, + OPT_MODE_UNPACK, + OPT_DATAPUBKEY, + OPT_SIGNPUBKEY, + OPT_SIGNPRIVATE, + OPT_SIGNPRIVATE_PEM, + OPT_PEM_ALGORITHM, + OPT_EXTERNAL_SIGNER, + 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 }, + {"signprivate_pem", 1, 0, OPT_SIGNPRIVATE_PEM }, + {"pem_algorithm", 1, 0, OPT_PEM_ALGORITHM }, + {"externalsigner", 1, 0, OPT_EXTERNAL_SIGNER }, + {"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.\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 */ +static int Pack(const char* outfile, const char* datapubkey, + const char* signprivate, + const char* signprivate_pem, uint64_t pem_algorithm, + uint64_t flags, + const char* external_signer) { + 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_pem) { + if (pem_algorithm >= kNumAlgorithms) { + fprintf(stderr, "vbutil_keyblock: Invalid --pem_algorithm %" PRIu64 "\n", + pem_algorithm); + return 1; + } + if (external_signer) { + /* External signing uses the PEM file directly. */ + block = KeyBlockCreate_external(data_key, + signprivate_pem, pem_algorithm, + flags, + external_signer); + } else { + signing_key = PrivateKeyReadPem(signprivate_pem, pem_algorithm); + if (!signing_key) { + fprintf(stderr, "vbutil_keyblock: Error reading signing key.\n"); + return 1; + } + block = KeyBlockCreate(data_key, signing_key, flags); + } + } else { + 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 && signpubkey) { + 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; + } + free(sign_key); + } + + printf("Key block file: %s\n", infile); + printf("Signature %s\n", sign_key ? "valid" : "ignored"); + printf("Flags: %" PRIu64 " ", block->key_block_flags); + if (block->key_block_flags & KEY_BLOCK_FLAG_DEVELOPER_0) + printf(" !DEV"); + if (block->key_block_flags & KEY_BLOCK_FLAG_DEVELOPER_1) + printf(" DEV"); + if (block->key_block_flags & KEY_BLOCK_FLAG_RECOVERY_0) + printf(" !REC"); + if (block->key_block_flags & KEY_BLOCK_FLAG_RECOVERY_1) + printf(" REC"); + printf("\n"); + + 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); + printf("Data key sha1sum: "); + PrintPubKeySha1Sum(data_key); + printf("\n"); + + 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 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 *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_SIGNPRIVATE_PEM: + signprivate_pem = optarg; + break; + + case OPT_PEM_ALGORITHM: + pem_algorithm = strtoul(optarg, &e, 0); + if (!*optarg || (e && *e)) { + fprintf(stderr, "Invalid --pem_algorithm\n"); + parse_error = 1; + } else { + is_pem_algorithm = 1; + } + break; + + case OPT_EXTERNAL_SIGNER: + external_signer = optarg; + break; + + case OPT_FLAGS: + flags = strtoul(optarg, &e, 0); + if (!*optarg || (e && *e)) { + fprintf(stderr, "Invalid --flags\n"); + parse_error = 1; + } + break; + } + } + + /* Check if the right combination of options was provided. */ + if (signprivate && signprivate_pem) { + fprintf(stderr, "Only one of --signprivate or --signprivate_pem must" + " be specified\n"); + parse_error = 1; + } + + if (signprivate_pem && !is_pem_algorithm) { + fprintf(stderr, "--pem_algorithm must be used with --signprivate_pem\n"); + parse_error = 1; + } + + if (external_signer && !signprivate_pem) { + fprintf(stderr, "--externalsigner must be used with --signprivate_pem" + "\n"); + parse_error = 1; + } + + if (parse_error) + return PrintHelp(progname); + + switch(mode) { + case OPT_MODE_PACK: + return Pack(filename, datapubkey, signprivate, + signprivate_pem, pem_algorithm, + flags, + external_signer); + case OPT_MODE_UNPACK: + return Unpack(filename, datapubkey, signpubkey); + default: + printf("Must specify a mode.\n"); + return PrintHelp(progname); + } +} + +DECLARE_FUTIL_COMMAND(vbutil_keyblock, do_vbutil_keyblock, + "Verified boot key block utility"); |