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 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 "futility.h"
16 #include "host_common.h"
17 #include "host_key21.h"
18 #include "util_misc.h"
19 #include "vb1_helper.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 OPT_HELP,
30 };
31
32 static const struct option long_opts[] = {
33 {"key", 1, 0, OPT_INKEY},
34 {"version", 1, 0, OPT_KEY_VERSION},
35 {"algorithm", 1, 0, OPT_ALGORITHM},
36 {"pack", 1, 0, OPT_MODE_PACK},
37 {"unpack", 1, 0, OPT_MODE_UNPACK},
38 {"copyto", 1, 0, OPT_COPYTO},
39 {"help", 0, 0, OPT_HELP},
40 {NULL, 0, 0, 0}
41 };
42
print_help(int argc,char * argv[])43 static void print_help(int argc, char *argv[])
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", argv[0]);
55
56 for (enum vb2_crypto_algorithm i = 0; i < VB2_ALG_COUNT; i++) {
57 printf(" %d = (%s)\n",
58 i, vb2_get_crypto_algorithm_name(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", argv[0]);
67 }
68
69 /* 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 static int do_pack(const char *infile, const char *outfile, uint32_t algorithm,
71 uint32_t version)
72 {
73 if (!infile || !outfile) {
74 ERROR("vbutil_key: Must specify --in and --out\n");
75 return 1;
76 }
77
78 struct vb2_packed_key *pubkey =
79 vb2_read_packed_keyb(infile, algorithm, version);
80 if (pubkey) {
81 if (vb2_write_packed_key(outfile, pubkey)) {
82 ERROR("vbutil_key: Error writing key.\n");
83 free(pubkey);
84 return 1;
85 }
86 free(pubkey);
87 return 0;
88 }
89
90 struct vb2_private_key *privkey =
91 vb2_read_private_key_pem(infile, algorithm);
92 if (privkey) {
93 if (VB2_SUCCESS != vb2_write_private_key(outfile, privkey)) {
94 ERROR("vbutil_key: Error writing key.\n");
95 free(privkey);
96 return 1;
97 }
98 free(privkey);
99 return 0;
100 }
101
102 FATAL("Unable to parse either .keyb or .pem from %s\n", infile);
103 return 1;
104 }
105
106 /* Unpack a .vbpubk, .vbprivk, or .vbprik2 */
do_unpack(const char * infile,const char * outfile)107 static int do_unpack(const char *infile, const char *outfile)
108 {
109 struct vb2_packed_key *pubkey;
110
111 if (!infile) {
112 ERROR("Need file to unpack\n");
113 return 1;
114 }
115
116 pubkey = vb2_read_packed_key(infile);
117 if (pubkey) {
118 printf("Public Key file: %s\n", infile);
119 printf("Algorithm: %u %s\n", pubkey->algorithm,
120 vb2_get_crypto_algorithm_name(pubkey->algorithm));
121 printf("Key Version: %u\n", pubkey->key_version);
122 printf("Key sha1sum: %s\n",
123 packed_key_sha1_string(pubkey));
124 if (outfile &&
125 VB2_SUCCESS != vb2_write_packed_key(outfile, pubkey)) {
126 ERROR("butil_key: Error writing key copy\n");
127 free(pubkey);
128 return 1;
129 }
130 free(pubkey);
131 return 0;
132 }
133
134 struct vb2_private_key *privkey = vb2_read_private_key(infile);
135 if (privkey) {
136 printf("Private Key file: %s\n", infile);
137
138 enum vb2_crypto_algorithm alg =
139 vb2_get_crypto_algorithm(privkey->hash_alg,
140 privkey->sig_alg);
141 printf("Algorithm: %u %s\n", alg,
142 vb2_get_crypto_algorithm_name(alg));
143 if (outfile &&
144 VB2_SUCCESS != vb2_write_private_key(outfile, privkey)) {
145 ERROR("vbutil_key: Error writing key copy\n");
146 free(privkey);
147 return 1;
148 }
149 free(privkey);
150 return 0;
151 }
152
153 FATAL("Unable to parse either .vbpubk or vbprivk from %s\n", infile);
154 return 1;
155 }
156
do_vbutil_key(int argc,char * argv[])157 static int do_vbutil_key(int argc, char *argv[])
158 {
159
160 char *infile = NULL;
161 char *outfile = NULL;
162 int mode = 0;
163 int parse_error = 0;
164 uint32_t version = 1;
165 uint32_t algorithm = VB2_ALG_COUNT;
166 char *e;
167 int i;
168
169 while ((i = getopt_long(argc, argv, "", long_opts, NULL)) != -1) {
170 switch (i) {
171 case '?':
172 /* Unhandled option */
173 FATAL("Unknown option\n");
174 parse_error = 1;
175 break;
176 case OPT_HELP:
177 print_help(argc, argv);
178 return !!parse_error;
179
180 case OPT_INKEY:
181 infile = optarg;
182 break;
183
184 case OPT_KEY_VERSION:
185 version = strtoul(optarg, &e, 0);
186 if (!*optarg || (e && *e)) {
187 FATAL("Invalid --version\n");
188 parse_error = 1;
189 }
190 break;
191
192 case OPT_ALGORITHM:
193 algorithm = strtoul(optarg, &e, 0);
194 if (!*optarg || (e && *e)) {
195 FATAL("Invalid --algorithm\n");
196 parse_error = 1;
197 }
198 break;
199
200 case OPT_MODE_PACK:
201 mode = i;
202 outfile = optarg;
203 break;
204
205 case OPT_MODE_UNPACK:
206 mode = i;
207 infile = optarg;
208 break;
209
210 case OPT_COPYTO:
211 outfile = optarg;
212 break;
213 }
214 }
215
216 if (parse_error) {
217 print_help(argc, argv);
218 return 1;
219 }
220
221 switch (mode) {
222 case OPT_MODE_PACK:
223 return do_pack(infile, outfile, algorithm, version);
224 case OPT_MODE_UNPACK:
225 return do_unpack(infile, outfile);
226 default:
227 printf("Must specify a mode.\n");
228 print_help(argc, argv);
229 return 1;
230 }
231 }
232
233 DECLARE_FUTIL_COMMAND(vbutil_key, do_vbutil_key, VBOOT_VERSION_1_0,
234 "Wraps RSA keys with vboot headers");
235