Home | History | Annotate | Download | only in futility
      1 /* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
      2  * Use of this source code is governed by a BSD-style license that can be
      3  * found in the LICENSE file.
      4  *
      5  * Verified boot key utility
      6  */
      7 
      8 #include <getopt.h>
      9 #include <inttypes.h>		/* For PRIu64 */
     10 #include <stdarg.h>
     11 #include <stdio.h>
     12 #include <stdlib.h>
     13 #include <string.h>
     14 
     15 #include "cryptolib.h"
     16 #include "futility.h"
     17 #include "host_common.h"
     18 #include "util_misc.h"
     19 #include "vboot_common.h"
     20 
     21 /* Command line options */
     22 enum {
     23 	OPT_INKEY = 1000,
     24 	OPT_KEY_VERSION,
     25 	OPT_ALGORITHM,
     26 	OPT_MODE_PACK,
     27 	OPT_MODE_UNPACK,
     28 	OPT_COPYTO,
     29 };
     30 
     31 static const struct option long_opts[] = {
     32 	{"key", 1, 0, OPT_INKEY},
     33 	{"version", 1, 0, OPT_KEY_VERSION},
     34 	{"algorithm", 1, 0, OPT_ALGORITHM},
     35 	{"pack", 1, 0, OPT_MODE_PACK},
     36 	{"unpack", 1, 0, OPT_MODE_UNPACK},
     37 	{"copyto", 1, 0, OPT_COPYTO},
     38 	{NULL, 0, 0, 0}
     39 };
     40 
     41 static void print_help(const char *progname)
     42 {
     43 	int i;
     44 
     45 	printf("\n"
     46 	       "Usage:  " MYNAME " %s --pack <outfile> [PARAMETERS]\n"
     47 	       "\n"
     48 	       "  Required parameters:\n"
     49 	       "    --key <infile>              RSA key file (.keyb or .pem)\n"
     50 	       "    --version <number>          Key version number "
     51 	       "(required for .keyb,\n"
     52 	       "                                  ignored for .pem)\n"
     53 	       "    --algorithm <number>        "
     54 	       "Signing algorithm to use with key:\n", progname);
     55 
     56 	for (i = 0; i < kNumAlgorithms; i++) {
     57 		printf("                                  %d = (%s)\n",
     58 		       i, algo_strings[i]);
     59 	}
     60 
     61 	printf("\nOR\n\n"
     62 	       "Usage:  " MYNAME " %s --unpack <infile>\n"
     63 	       "\n"
     64 	       "  Optional parameters:\n"
     65 	       "    --copyto <file>             "
     66 	       "Write a copy of the key to this file.\n\n", progname);
     67 }
     68 
     69 /* Pack a .keyb file into a .vbpubk, or a .pem into a .vbprivk */
     70 static int Pack(const char *infile, const char *outfile, uint64_t algorithm,
     71 		uint64_t version)
     72 {
     73 	VbPublicKey *pubkey;
     74 	VbPrivateKey *privkey;
     75 
     76 	if (!infile || !outfile) {
     77 		fprintf(stderr, "vbutil_key: Must specify --in and --out\n");
     78 		return 1;
     79 	}
     80 
     81 	pubkey = PublicKeyReadKeyb(infile, algorithm, version);
     82 	if (pubkey) {
     83 		if (0 != PublicKeyWrite(outfile, pubkey)) {
     84 			fprintf(stderr, "vbutil_key: Error writing key.\n");
     85 			return 1;
     86 		}
     87 		free(pubkey);
     88 		return 0;
     89 	}
     90 
     91 	privkey = PrivateKeyReadPem(infile, algorithm);
     92 	if (privkey) {
     93 		if (0 != PrivateKeyWrite(outfile, privkey)) {
     94 			fprintf(stderr, "vbutil_key: Error writing key.\n");
     95 			return 1;
     96 		}
     97 		free(privkey);
     98 		return 0;
     99 	}
    100 
    101 	VbExError("Unable to parse either .keyb or .pem from %s\n", infile);
    102 	return 1;
    103 }
    104 
    105 /* Unpack a .vbpubk or .vbprivk */
    106 static int Unpack(const char *infile, const char *outfile)
    107 {
    108 	VbPublicKey *pubkey;
    109 	VbPrivateKey *privkey;
    110 
    111 	if (!infile) {
    112 		fprintf(stderr, "Need file to unpack\n");
    113 		return 1;
    114 	}
    115 
    116 	pubkey = PublicKeyRead(infile);
    117 	if (pubkey) {
    118 		printf("Public Key file:   %s\n", infile);
    119 		printf("Algorithm:         %" PRIu64 " %s\n", pubkey->algorithm,
    120 		       (pubkey->algorithm < kNumAlgorithms ?
    121 			algo_strings[pubkey->algorithm] : "(invalid)"));
    122 		printf("Key Version:       %" PRIu64 "\n", pubkey->key_version);
    123 		printf("Key sha1sum:       ");
    124 		PrintPubKeySha1Sum(pubkey);
    125 		printf("\n");
    126 		if (outfile) {
    127 			if (0 != PublicKeyWrite(outfile, pubkey)) {
    128 				fprintf(stderr,
    129 					"vbutil_key: Error writing key copy\n");
    130 				free(pubkey);
    131 				return 1;
    132 			}
    133 		}
    134 		free(pubkey);
    135 		return 0;
    136 	}
    137 
    138 	privkey = PrivateKeyRead(infile);
    139 	if (privkey) {
    140 		printf("Private Key file:  %s\n", infile);
    141 		printf("Algorithm:         %" PRIu64 " %s\n",
    142 		       privkey->algorithm,
    143 		       (privkey->algorithm <
    144 			kNumAlgorithms ? algo_strings[privkey->
    145 						      algorithm] :
    146 			"(invalid)"));
    147 		if (outfile) {
    148 			if (0 != PrivateKeyWrite(outfile, privkey)) {
    149 				fprintf(stderr,
    150 					"vbutil_key: Error writing key copy\n");
    151 				free(privkey);
    152 				return 1;
    153 			}
    154 		}
    155 		free(privkey);
    156 		return 0;
    157 	}
    158 
    159 	VbExError("Unable to parse either .vbpubk or vbprivk from %s\n",
    160 		  infile);
    161 	return 1;
    162 }
    163 
    164 static int do_vbutil_key(int argc, char *argv[])
    165 {
    166 
    167 	char *infile = NULL;
    168 	char *outfile = NULL;
    169 	int mode = 0;
    170 	int parse_error = 0;
    171 	uint64_t version = 1;
    172 	uint64_t algorithm = kNumAlgorithms;
    173 	char *e;
    174 	int i;
    175 
    176 	while ((i = getopt_long(argc, argv, "", long_opts, NULL)) != -1) {
    177 		switch (i) {
    178 		case '?':
    179 			/* Unhandled option */
    180 			VbExError("Unknown option\n");
    181 			parse_error = 1;
    182 			break;
    183 
    184 		case OPT_INKEY:
    185 			infile = optarg;
    186 			break;
    187 
    188 		case OPT_KEY_VERSION:
    189 			version = strtoul(optarg, &e, 0);
    190 			if (!*optarg || (e && *e)) {
    191 				VbExError("Invalid --version\n");
    192 				parse_error = 1;
    193 			}
    194 			break;
    195 
    196 		case OPT_ALGORITHM:
    197 			algorithm = strtoul(optarg, &e, 0);
    198 			if (!*optarg || (e && *e)) {
    199 				VbExError("Invalid --algorithm\n");
    200 				parse_error = 1;
    201 			}
    202 			break;
    203 
    204 		case OPT_MODE_PACK:
    205 			mode = i;
    206 			outfile = optarg;
    207 			break;
    208 
    209 		case OPT_MODE_UNPACK:
    210 			mode = i;
    211 			infile = optarg;
    212 			break;
    213 
    214 		case OPT_COPYTO:
    215 			outfile = optarg;
    216 			break;
    217 		}
    218 	}
    219 
    220 	if (parse_error) {
    221 		print_help(argv[0]);
    222 		return 1;
    223 	}
    224 
    225 	switch (mode) {
    226 	case OPT_MODE_PACK:
    227 		return Pack(infile, outfile, algorithm, version);
    228 	case OPT_MODE_UNPACK:
    229 		return Unpack(infile, outfile);
    230 	default:
    231 		printf("Must specify a mode.\n");
    232 		print_help(argv[0]);
    233 		return 1;
    234 	}
    235 }
    236 
    237 DECLARE_FUTIL_COMMAND(vbutil_key, do_vbutil_key,
    238 		      VBOOT_VERSION_1_0,
    239 		      "Wraps RSA keys with vboot headers",
    240 		      print_help);
    241