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 
print_help(const char * progname)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 */
Pack(const char * infile,const char * outfile,uint64_t algorithm,uint64_t version)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 */
Unpack(const char * infile,const char * outfile)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 
do_vbutil_key(int argc,char * argv[])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