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