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 block utility
6 */
7
8 #include <getopt.h>
9 #include <stdint.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13
14 #include "cryptolib.h"
15 #include "futility.h"
16 #include "host_common.h"
17 #include "util_misc.h"
18 #include "vboot_common.h"
19
20 /* Command line options */
21 enum {
22 OPT_MODE_PACK = 1000,
23 OPT_MODE_UNPACK,
24 OPT_DATAPUBKEY,
25 OPT_SIGNPUBKEY,
26 OPT_SIGNPRIVATE,
27 OPT_SIGNPRIVATE_PEM,
28 OPT_PEM_ALGORITHM,
29 OPT_EXTERNAL_SIGNER,
30 OPT_FLAGS,
31 };
32
33 static const struct option long_opts[] = {
34 {"pack", 1, 0, OPT_MODE_PACK},
35 {"unpack", 1, 0, OPT_MODE_UNPACK},
36 {"datapubkey", 1, 0, OPT_DATAPUBKEY},
37 {"signpubkey", 1, 0, OPT_SIGNPUBKEY},
38 {"signprivate", 1, 0, OPT_SIGNPRIVATE},
39 {"signprivate_pem", 1, 0, OPT_SIGNPRIVATE_PEM},
40 {"pem_algorithm", 1, 0, OPT_PEM_ALGORITHM},
41 {"externalsigner", 1, 0, OPT_EXTERNAL_SIGNER},
42 {"flags", 1, 0, OPT_FLAGS},
43 {NULL, 0, 0, 0}
44 };
45
46 static const char usage[] =
47 "\n"
48 "Usage: " MYNAME " %s <--pack|--unpack> <file> [OPTIONS]\n"
49 "\n"
50 "For '--pack <file>', required OPTIONS are:\n"
51 " --datapubkey <file> Data public key in .vbpubk format\n"
52 "\n"
53 "Optional OPTIONS are:\n"
54 " --signprivate <file>"
55 " Signing private key in .vbprivk format.\n"
56 "OR\n"
57 " --signprivate_pem <file>\n"
58 " --pem_algorithm <algo>\n"
59 " Signing private key in .pem format and algorithm id.\n"
60 "(If one of the above arguments is not specified, the keyblock will\n"
61 "not be signed.)\n"
62 "\n"
63 " --flags <number> Specifies allowed use conditions.\n"
64 " --externalsigner \"cmd\""
65 " Use an external program cmd to calculate the signatures.\n"
66 "\n"
67 "For '--unpack <file>', optional OPTIONS are:\n"
68 " --signpubkey <file>"
69 " Signing public key in .vbpubk format. This is required to\n"
70 " verify a signed keyblock.\n"
71 " --datapubkey <file>"
72 " Write the data public key to this file.\n\n";
73
print_help(const char * progname)74 static void print_help(const char *progname)
75 {
76 printf(usage, progname);
77 }
78
79 /* Pack a .keyblock */
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)80 static int Pack(const char *outfile, const char *datapubkey,
81 const char *signprivate,
82 const char *signprivate_pem, uint64_t pem_algorithm,
83 uint64_t flags, const char *external_signer)
84 {
85 VbPublicKey *data_key;
86 VbPrivateKey *signing_key = NULL;
87 VbKeyBlockHeader *block;
88
89 if (!outfile) {
90 fprintf(stderr,
91 "vbutil_keyblock: Must specify output filename.\n");
92 return 1;
93 }
94 if (!datapubkey) {
95 fprintf(stderr,
96 "vbutil_keyblock: Must specify data public key.\n");
97 return 1;
98 }
99
100 data_key = PublicKeyRead(datapubkey);
101 if (!data_key) {
102 fprintf(stderr, "vbutil_keyblock: Error reading data key.\n");
103 return 1;
104 }
105
106 if (signprivate_pem) {
107 if (pem_algorithm >= kNumAlgorithms) {
108 fprintf(stderr,
109 "vbutil_keyblock: Invalid --pem_algorithm %"
110 PRIu64 "\n", pem_algorithm);
111 return 1;
112 }
113 if (external_signer) {
114 /* External signing uses the PEM file directly. */
115 block = KeyBlockCreate_external(data_key,
116 signprivate_pem,
117 pem_algorithm, flags,
118 external_signer);
119 } else {
120 signing_key =
121 PrivateKeyReadPem(signprivate_pem, pem_algorithm);
122 if (!signing_key) {
123 fprintf(stderr, "vbutil_keyblock:"
124 " Error reading signing key.\n");
125 return 1;
126 }
127 block = KeyBlockCreate(data_key, signing_key, flags);
128 }
129 } else {
130 if (signprivate) {
131 signing_key = PrivateKeyRead(signprivate);
132 if (!signing_key) {
133 fprintf(stderr, "vbutil_keyblock:"
134 " Error reading signing key.\n");
135 return 1;
136 }
137 }
138 block = KeyBlockCreate(data_key, signing_key, flags);
139 }
140
141 free(data_key);
142 if (signing_key)
143 free(signing_key);
144
145 if (0 != KeyBlockWrite(outfile, block)) {
146 fprintf(stderr, "vbutil_keyblock: Error writing key block.\n");
147 return 1;
148 }
149 free(block);
150 return 0;
151 }
152
Unpack(const char * infile,const char * datapubkey,const char * signpubkey)153 static int Unpack(const char *infile, const char *datapubkey,
154 const char *signpubkey)
155 {
156 VbPublicKey *data_key;
157 VbPublicKey *sign_key = NULL;
158 VbKeyBlockHeader *block;
159
160 if (!infile) {
161 fprintf(stderr, "vbutil_keyblock: Must specify filename\n");
162 return 1;
163 }
164
165 block = KeyBlockRead(infile);
166 if (!block) {
167 fprintf(stderr, "vbutil_keyblock: Error reading key block.\n");
168 return 1;
169 }
170
171 /* If the block is signed, then verify it with the signing public key,
172 * since KeyBlockRead() only verified the hash. */
173 if (block->key_block_signature.sig_size && signpubkey) {
174 sign_key = PublicKeyRead(signpubkey);
175 if (!sign_key) {
176 fprintf(stderr,
177 "vbutil_keyblock: Error reading signpubkey.\n");
178 return 1;
179 }
180 if (0 !=
181 KeyBlockVerify(block, block->key_block_size, sign_key, 0)) {
182 fprintf(stderr, "vbutil_keyblock:"
183 " Error verifying key block.\n");
184 return 1;
185 }
186 free(sign_key);
187 }
188
189 printf("Key block file: %s\n", infile);
190 printf("Signature %s\n", sign_key ? "valid" : "ignored");
191 printf("Flags: %" PRIu64 " ", block->key_block_flags);
192 if (block->key_block_flags & KEY_BLOCK_FLAG_DEVELOPER_0)
193 printf(" !DEV");
194 if (block->key_block_flags & KEY_BLOCK_FLAG_DEVELOPER_1)
195 printf(" DEV");
196 if (block->key_block_flags & KEY_BLOCK_FLAG_RECOVERY_0)
197 printf(" !REC");
198 if (block->key_block_flags & KEY_BLOCK_FLAG_RECOVERY_1)
199 printf(" REC");
200 printf("\n");
201
202 data_key = &block->data_key;
203 printf("Data key algorithm: %" PRIu64 " %s\n", data_key->algorithm,
204 (data_key->algorithm < kNumAlgorithms ?
205 algo_strings[data_key->algorithm] : "(invalid)"));
206 printf("Data key version: %" PRIu64 "\n", data_key->key_version);
207 printf("Data key sha1sum: ");
208 PrintPubKeySha1Sum(data_key);
209 printf("\n");
210
211 if (datapubkey) {
212 if (0 != PublicKeyWrite(datapubkey, data_key)) {
213 fprintf(stderr, "vbutil_keyblock:"
214 " unable to write public key\n");
215 return 1;
216 }
217 }
218
219 free(block);
220 return 0;
221 }
222
do_vbutil_keyblock(int argc,char * argv[])223 static int do_vbutil_keyblock(int argc, char *argv[])
224 {
225
226 char *filename = NULL;
227 char *datapubkey = NULL;
228 char *signpubkey = NULL;
229 char *signprivate = NULL;
230 char *signprivate_pem = NULL;
231 char *external_signer = NULL;
232 uint64_t flags = 0;
233 uint64_t pem_algorithm = 0;
234 int is_pem_algorithm = 0;
235 int mode = 0;
236 int parse_error = 0;
237 char *e;
238 int i;
239
240 while ((i = getopt_long(argc, argv, "", long_opts, NULL)) != -1) {
241 switch (i) {
242 case '?':
243 /* Unhandled option */
244 printf("Unknown option\n");
245 parse_error = 1;
246 break;
247
248 case OPT_MODE_PACK:
249 case OPT_MODE_UNPACK:
250 mode = i;
251 filename = optarg;
252 break;
253
254 case OPT_DATAPUBKEY:
255 datapubkey = optarg;
256 break;
257
258 case OPT_SIGNPUBKEY:
259 signpubkey = optarg;
260 break;
261
262 case OPT_SIGNPRIVATE:
263 signprivate = optarg;
264 break;
265
266 case OPT_SIGNPRIVATE_PEM:
267 signprivate_pem = optarg;
268 break;
269
270 case OPT_PEM_ALGORITHM:
271 pem_algorithm = strtoul(optarg, &e, 0);
272 if (!*optarg || (e && *e)) {
273 fprintf(stderr, "Invalid --pem_algorithm\n");
274 parse_error = 1;
275 } else {
276 is_pem_algorithm = 1;
277 }
278 break;
279
280 case OPT_EXTERNAL_SIGNER:
281 external_signer = optarg;
282 break;
283
284 case OPT_FLAGS:
285 flags = strtoul(optarg, &e, 0);
286 if (!*optarg || (e && *e)) {
287 fprintf(stderr, "Invalid --flags\n");
288 parse_error = 1;
289 }
290 break;
291 }
292 }
293
294 /* Check if the right combination of options was provided. */
295 if (signprivate && signprivate_pem) {
296 fprintf(stderr,
297 "Only one of --signprivate or --signprivate_pem must"
298 " be specified\n");
299 parse_error = 1;
300 }
301
302 if (signprivate_pem && !is_pem_algorithm) {
303 fprintf(stderr, "--pem_algorithm must be used with"
304 " --signprivate_pem\n");
305 parse_error = 1;
306 }
307
308 if (external_signer && !signprivate_pem) {
309 fprintf(stderr,
310 "--externalsigner must be used with --signprivate_pem"
311 "\n");
312 parse_error = 1;
313 }
314
315 if (parse_error) {
316 print_help(argv[0]);
317 return 1;
318 }
319
320 switch (mode) {
321 case OPT_MODE_PACK:
322 return Pack(filename, datapubkey, signprivate,
323 signprivate_pem, pem_algorithm,
324 flags, external_signer);
325 case OPT_MODE_UNPACK:
326 return Unpack(filename, datapubkey, signpubkey);
327 default:
328 printf("Must specify a mode.\n");
329 print_help(argv[0]);
330 return 1;
331 }
332 }
333
334 DECLARE_FUTIL_COMMAND(vbutil_keyblock, do_vbutil_keyblock,
335 VBOOT_VERSION_1_0,
336 "Creates, signs, and verifies a keyblock",
337 print_help);
338