| /* 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); |
| } |
| } |