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