1 /* 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 10 #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 */ 27 enum { 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 38 static char *infile, *outfile, *outext; 39 static uint32_t opt_version = DEFAULT_VERSION; 40 enum vb2_hash_algorithm opt_hash_alg = DEFAULT_HASH; 41 static char *opt_desc; 42 static struct vb2_guid opt_guid; 43 44 static 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 52 static 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 77 static 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 151 done: 152 free(privkey); 153 free(pubkey); 154 free(keyb_data); 155 RSA_free(rsa_key); 156 return ret; 157 } 158 159 static 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 258 done: 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 268 static 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 398 DECLARE_FUTIL_COMMAND(create, do_create, 399 VBOOT_VERSION_ALL, 400 "Create a keypair from an RSA .pem file", 401 print_help); 402