blob: bd155d4fcb7610847ffab30a858c636f9417fbdd [file] [log] [blame]
Bill Richardson4e4c1962015-02-03 17:07:15 -08001/* Copyright 2015 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
6#include <getopt.h>
7#include <stdio.h>
8#include <unistd.h>
9
Bill Richardson4e4c1962015-02-03 17:07:15 -080010#include <openssl/pem.h>
11
12#include "2sysincludes.h"
13#include "2common.h"
14#include "2guid.h"
15#include "2rsa.h"
16#include "util_misc.h"
17#include "vb2_common.h"
18#include "vb2_struct.h"
19
20#include "host_key.h"
21#include "host_key2.h"
22#include "host_misc2.h"
23
24#include "futility.h"
25
26/* Command line options */
27enum {
28 OPT_OUTFILE = 1000,
29 OPT_VERSION,
30 OPT_DESC,
31 OPT_GUID,
32 OPT_HASH_ALG,
33};
34
35#define DEFAULT_VERSION 1
36#define DEFAULT_HASH VB2_HASH_SHA256;
37
38static char *infile, *outfile, *outext;
39static uint32_t opt_version = DEFAULT_VERSION;
40enum vb2_hash_algorithm opt_hash_alg = DEFAULT_HASH;
41static char *opt_desc;
42static struct vb2_guid opt_guid;
43
44static const struct option long_opts[] = {
45 {"version", 1, 0, OPT_VERSION},
46 {"desc", 1, 0, OPT_DESC},
47 {"guid", 1, 0, OPT_GUID},
48 {"hash_alg", 1, 0, OPT_HASH_ALG},
49 {NULL, 0, 0, 0}
50};
51
52static void print_help(const char *progname)
53{
54 struct vb2_text_vs_enum *entry;
55
56 printf("\n"
57"Usage: " MYNAME " %s [options] <INFILE> [<BASENAME>]\n", progname);
58 printf("\n"
59"Create a keypair from an RSA key (.pem file).\n"
60"\n"
61"Options:\n"
62"\n"
63" --version <number> Key version (default %d)\n"
64" --hash_alg <number> Hashing algorithm to use:\n",
65 DEFAULT_VERSION);
66 for (entry = vb2_text_vs_hash; entry->name; entry++)
67 printf(" %d / %s%s\n",
68 entry->num, entry->name,
69 entry->num == VB2_HASH_SHA256 ? " (default)" : "");
70 printf(
71" --guid <guid> Identifier for this keypair (vb21 only)\n"
72" --desc <text> Human-readable description (vb21 only)\n"
73"\n");
74
75}
76
77static int vb1_make_keypair()
78{
79 VbPrivateKey *privkey = 0;
80 VbPublicKey *pubkey = 0;
81 RSA *rsa_key = 0;
82 uint8_t *keyb_data = 0;
83 uint32_t keyb_size;
84 enum vb2_signature_algorithm sig_alg;
85 uint64_t vb1_algorithm;
86 FILE *fp;
87 int ret = 1;
88
89 fp = fopen(infile, "rb");
90 if (!fp) {
91 fprintf(stderr, "Unable to open %s\n", infile);
92 goto done;
93 }
94
95 rsa_key = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL);
96 fclose(fp);
97
98 if (!rsa_key) {
99 fprintf(stderr, "Unable to read RSA key from %s\n", infile);
100 goto done;
101 }
102
103 sig_alg = vb2_rsa_sig_alg(rsa_key);
104 if (sig_alg == VB2_SIG_INVALID) {
105 fprintf(stderr, "Unsupported sig algorithm in RSA key\n");
106 goto done;
107 }
108
109 /* combine the sig_alg with the hash_alg to get the vb1 algorithm */
110 vb1_algorithm = (sig_alg - VB2_SIG_RSA1024) * 3
111 + opt_hash_alg - VB2_HASH_SHA1;
112
113 /* Create the private key */
114 privkey = (VbPrivateKey *)malloc(sizeof(VbPrivateKey));
115 if (!privkey)
116 goto done;
117
118 privkey->rsa_private_key = rsa_key;
119 privkey->algorithm = vb1_algorithm;
120
121 /* Write it out */
122 strcpy(outext, ".vbprivk");
123 if (0 != PrivateKeyWrite(outfile, privkey)) {
124 fprintf(stderr, "unable to write private key\n");
125 goto done;
126 }
127 fprintf(stderr, "wrote %s\n", outfile);
128
129 /* Create the public key */
130 ret = vb_keyb_from_rsa(rsa_key, &keyb_data, &keyb_size);
131 if (ret) {
132 fprintf(stderr, "couldn't extract the public key\n");
133 goto done;
134 }
135
136 pubkey = PublicKeyAlloc(keyb_size, vb1_algorithm, opt_version);
137 if (!pubkey)
138 goto done;
139 memcpy(GetPublicKeyData(pubkey), keyb_data, keyb_size);
140
141 /* Write it out */
142 strcpy(outext, ".vbpubk");
143 if (0 != PublicKeyWrite(outfile, pubkey)) {
144 fprintf(stderr, "unable to write public key\n");
145 goto done;
146 }
147 fprintf(stderr, "wrote %s\n", outfile);
148
149 ret = 0;
150
151done:
152 free(privkey);
153 free(pubkey);
154 free(keyb_data);
155 RSA_free(rsa_key);
156 return ret;
157}
158
159static int vb2_make_keypair()
160{
161 struct vb2_private_key *privkey = 0;
162 struct vb2_public_key *pubkey = 0;
163 RSA *rsa_key = 0;
164 uint8_t *keyb_data = 0;
165 uint32_t keyb_size;
166 enum vb2_signature_algorithm sig_alg;
167 uint8_t *pubkey_buf = 0;
168
169 FILE *fp;
170 int ret = 1;
171
172 fp = fopen(infile, "rb");
173 if (!fp) {
174 fprintf(stderr, "Unable to open %s\n", infile);
175 goto done;
176 }
177
178 rsa_key = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL);
179 fclose(fp);
180
181 if (!rsa_key) {
182 fprintf(stderr, "Unable to read RSA key from %s\n", infile);
183 goto done;
184 }
185
186 sig_alg = vb2_rsa_sig_alg(rsa_key);
187 if (sig_alg == VB2_SIG_INVALID) {
188 fprintf(stderr, "Unsupported sig algorithm in RSA key\n");
189 goto done;
190 }
191
192 /* Create the private key */
193 privkey = calloc(1, sizeof(*privkey));
194 if (!privkey) {
195 fprintf(stderr, "Unable to allocate the private key\n");
196 goto done;
197 }
198 privkey->rsa_private_key = rsa_key;
199 privkey->sig_alg = sig_alg;
200 privkey->hash_alg = opt_hash_alg;
201 privkey->guid = opt_guid;
202 if (opt_desc && vb2_private_key_set_desc(privkey, opt_desc)) {
203 fprintf(stderr, "Unable to set the private key description\n");
204 goto done;
205 }
206
207 /* Write it out */
208 strcpy(outext, ".vbprik2");
209 if (vb2_private_key_write(privkey, outfile)) {
210 fprintf(stderr, "unable to write private key\n");
211 goto done;
212 }
213 fprintf(stderr, "wrote %s\n", outfile);
214
215 /* Create the public key */
216 if (vb2_public_key_alloc(&pubkey, sig_alg)) {
217 fprintf(stderr, "Unable to allocate the public key\n");
218 goto done;
219 }
220
221 /* Extract the keyb blob */
222 if (vb_keyb_from_rsa(rsa_key, &keyb_data, &keyb_size)) {
223 fprintf(stderr, "Couldn't extract the public key\n");
224 goto done;
225 }
226
227 /*
228 * Copy the keyb blob to the public key's buffer, because that's where
229 * vb2_unpack_key_data() and vb2_public_key_pack() expect to find it.
230 */
231 pubkey_buf = vb2_public_key_packed_data(pubkey);
232 memcpy(pubkey_buf, keyb_data, keyb_size);
233
234 /* Fill in the internal struct pointers */
235 if (vb2_unpack_key_data(pubkey, pubkey_buf, keyb_size)) {
236 fprintf(stderr, "Unable to unpack the public key blob\n");
237 goto done;
238 }
239
240 pubkey->hash_alg = opt_hash_alg;
241 pubkey->version = opt_version;
242 memcpy((struct vb2_guid *)pubkey->guid, &opt_guid, sizeof(opt_guid));
243 if (opt_desc && vb2_public_key_set_desc(pubkey, opt_desc)) {
244 fprintf(stderr, "Unable to set pubkey description\n");
245 goto done;
246 }
247
248 /* Write it out */
249 strcpy(outext, ".vbpubk2");
250 if (vb2_public_key_write(pubkey, outfile)) {
251 fprintf(stderr, "unable to write public key\n");
252 goto done;
253 }
254 fprintf(stderr, "wrote %s\n", outfile);
255
256 ret = 0;
257
258done:
259 RSA_free(rsa_key);
260 if (privkey) /* prevent double-free */
261 privkey->rsa_private_key = 0;
262 vb2_private_key_free(privkey);
263 vb2_public_key_free(pubkey);
264 free(keyb_data);
265 return ret;
266}
267
268static int do_create(int argc, char *argv[])
269{
270 int errorcnt = 0;
271 char *e, *s;
272 int i, r, len, remove_ext = 0;
273 const struct vb2_text_vs_enum *entry;
274
275 while ((i = getopt_long(argc, argv, "", long_opts, NULL)) != -1) {
276 switch (i) {
277
278 case OPT_VERSION:
279 opt_version = strtoul(optarg, &e, 0);
280 if (!*optarg || (e && *e)) {
281 fprintf(stderr,
282 "invalid version \"%s\"\n", optarg);
283 errorcnt = 1;
284 }
285 break;
286
287 case OPT_DESC:
288 opt_desc = optarg;
289 break;
290
291 case OPT_GUID:
292 if (VB2_SUCCESS != vb2_str_to_guid(optarg,
293 &opt_guid)) {
294 fprintf(stderr, "invalid guid \"%s\"\n",
295 optarg);
296 errorcnt = 1;
297 }
298 break;
299
300 case OPT_HASH_ALG:
301 /* try string first */
302 entry = vb2_lookup_by_name(vb2_text_vs_hash, optarg);
303 if (entry) {
304 opt_hash_alg = entry->num;
305 break;
306 }
307 /* fine, try number */
308 opt_hash_alg = strtoul(optarg, &e, 0);
309 if (!*optarg || (e && *e)) {
310 fprintf(stderr,
311 "invalid hash_alg \"%s\"\n", optarg);
312 errorcnt++;
313 break;
314 }
315 if (!vb2_lookup_by_num(vb2_text_vs_hash,
316 opt_hash_alg)) {
317 fprintf(stderr,
318 "Hash algorithm %d is unsupported\n",
319 opt_hash_alg);
320 errorcnt++;
321 }
322 break;
323
324 case '?':
325 if (optopt)
326 fprintf(stderr, "Unrecognized option: -%c\n",
327 optopt);
328 else
329 fprintf(stderr, "Unrecognized option\n");
330 errorcnt++;
331 break;
332 case ':':
333 fprintf(stderr, "Missing argument to -%c\n", optopt);
334 errorcnt++;
335 break;
336 case 0: /* handled option */
337 break;
338 default:
339 DIE;
340 }
341 }
342
343 /* If we don't have an input file already, we need one */
344 if (!infile) {
345 if (argc - optind <= 0) {
346 fprintf(stderr, "ERROR: missing input filename\n");
347 errorcnt++;
348 } else {
349 infile = argv[optind++];
350 }
351 }
352
353 if (errorcnt) {
354 print_help(argv[0]);
355 return 1;
356 }
357
358 /* Decide how to determine the output filenames. */
359 if (argc > optind) {
360 s = argv[optind++]; /* just use this */
361 } else {
362 s = infile; /* based on pem file name */
363 remove_ext = 1;
364 }
365
366 /* Make an extra-large copy to leave room for filename extensions */
367 len = strlen(s) + 20;
368 outfile = (char *)malloc(len);
369 if (!outfile) {
370 fprintf(stderr, "ERROR: malloc() failed\n");
371 return 1;
372 }
373 strcpy(outfile, s);
374
375 if (remove_ext) {
376 /* Find the last '/' if any, then the last '.' before that. */
377 s = strrchr(outfile, '/');
378 if (!s)
379 s = outfile;
380 s = strrchr(s, '.');
381 /* Cut off the extension */
382 if (s)
383 *s = '\0';
384 }
385 /* Remember that spot for later */
386 outext = outfile + strlen(outfile);
387
388 /* Okay, do it */
389 if (vboot_version == VBOOT_VERSION_1_0)
390 r = vb1_make_keypair();
391 else
392 r = vb2_make_keypair();
393
394 free(outfile);
395 return r;
396}
397
398DECLARE_FUTIL_COMMAND(create, do_create,
399 VBOOT_VERSION_ALL,
400 "Create a keypair from an RSA .pem file",
401 print_help);