xref: /aosp_15_r20/external/vboot_reference/futility/cmd_vbutil_keyblock.c (revision 8617a60d3594060b7ecbd21bc622a7c14f3cf2bc)
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