123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416 |
- /* Copyright 2015 The Chromium OS Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
- #include <getopt.h>
- #include <stdio.h>
- #include <unistd.h>
- #include <openssl/pem.h>
- #include "2sysincludes.h"
- #include "2common.h"
- #include "2id.h"
- #include "2rsa.h"
- #include "2sha.h"
- #include "util_misc.h"
- #include "vb2_common.h"
- #include "vb21_common.h"
- #include "host_key.h"
- #include "host_key2.h"
- #include "host_misc2.h"
- #include "futility.h"
- #include "futility_options.h"
- /* Command line options */
- enum {
- OPT_OUTFILE = 1000,
- OPT_VERSION,
- OPT_DESC,
- OPT_ID,
- OPT_HASH_ALG,
- OPT_HELP,
- };
- #define DEFAULT_VERSION 1
- #define DEFAULT_HASH VB2_HASH_SHA256;
- static char *infile, *outfile, *outext;
- static uint32_t opt_version = DEFAULT_VERSION;
- enum vb2_hash_algorithm opt_hash_alg = DEFAULT_HASH;
- static char *opt_desc;
- static struct vb2_id opt_id;
- static int force_id;
- static const struct option long_opts[] = {
- {"version", 1, 0, OPT_VERSION},
- {"desc", 1, 0, OPT_DESC},
- {"id", 1, 0, OPT_ID},
- {"hash_alg", 1, 0, OPT_HASH_ALG},
- {"help", 0, 0, OPT_HELP},
- {NULL, 0, 0, 0}
- };
- static void print_help(int argc, char *argv[])
- {
- const struct vb2_text_vs_enum *entry;
- printf("\n"
- "Usage: " MYNAME " %s [options] <INFILE> [<BASENAME>]\n", argv[0]);
- printf("\n"
- "Create a keypair from an RSA key (.pem file).\n"
- "\n"
- "Options:\n"
- "\n"
- " --version <number> Key version (default %d)\n"
- " --hash_alg <number> Hashing algorithm to use:\n",
- DEFAULT_VERSION);
- for (entry = vb2_text_vs_hash; entry->name; entry++)
- printf(" %d / %s%s\n",
- entry->num, entry->name,
- entry->num == VB2_HASH_SHA256 ? " (default)" : "");
- printf(
- " --id <id> Identifier for this keypair (vb21 only)\n"
- " --desc <text> Human-readable description (vb21 only)\n"
- "\n");
- }
- static int vb1_make_keypair()
- {
- struct vb2_private_key *privkey = NULL;
- struct vb2_packed_key *pubkey = NULL;
- struct rsa_st *rsa_key = NULL;
- uint8_t *keyb_data = 0;
- uint32_t keyb_size;
- int ret = 1;
- FILE *fp = fopen(infile, "rb");
- if (!fp) {
- fprintf(stderr, "Unable to open %s\n", infile);
- goto done;
- }
- /* TODO: this is very similar to vb2_read_private_key_pem() */
- rsa_key = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL);
- fclose(fp);
- if (!rsa_key) {
- fprintf(stderr, "Unable to read RSA key from %s\n", infile);
- goto done;
- }
- enum vb2_signature_algorithm sig_alg = vb2_rsa_sig_alg(rsa_key);
- if (sig_alg == VB2_SIG_INVALID) {
- fprintf(stderr, "Unsupported sig algorithm in RSA key\n");
- goto done;
- }
- /* Combine the sig_alg with the hash_alg to get the vb1 algorithm */
- uint64_t vb1_algorithm =
- vb2_get_crypto_algorithm(opt_hash_alg, sig_alg);
- /* Create the private key */
- privkey = (struct vb2_private_key *)calloc(sizeof(*privkey), 1);
- if (!privkey)
- goto done;
- privkey->rsa_private_key = rsa_key;
- privkey->sig_alg = sig_alg;
- privkey->hash_alg = opt_hash_alg;
- /* Write it out */
- strcpy(outext, ".vbprivk");
- if (0 != vb2_write_private_key(outfile, privkey)) {
- fprintf(stderr, "unable to write private key\n");
- goto done;
- }
- fprintf(stderr, "wrote %s\n", outfile);
- /* Create the public key */
- ret = vb_keyb_from_rsa(rsa_key, &keyb_data, &keyb_size);
- if (ret) {
- fprintf(stderr, "couldn't extract the public key\n");
- goto done;
- }
- pubkey = vb2_alloc_packed_key(keyb_size, vb1_algorithm, opt_version);
- if (!pubkey)
- goto done;
- memcpy((uint8_t *)vb2_packed_key_data(pubkey), keyb_data, keyb_size);
- /* Write it out */
- strcpy(outext, ".vbpubk");
- if (VB2_SUCCESS != vb2_write_packed_key(outfile, pubkey)) {
- fprintf(stderr, "unable to write public key\n");
- goto done;
- }
- fprintf(stderr, "wrote %s\n", outfile);
- ret = 0;
- done:
- free(privkey);
- free(pubkey);
- free(keyb_data);
- RSA_free(rsa_key);
- return ret;
- }
- static int vb2_make_keypair()
- {
- struct vb2_private_key *privkey = 0;
- struct vb2_public_key *pubkey = 0;
- RSA *rsa_key = 0;
- uint8_t *keyb_data = 0;
- uint32_t keyb_size;
- enum vb2_signature_algorithm sig_alg;
- uint8_t *pubkey_buf = 0;
- int has_priv = 0;
- FILE *fp;
- int ret = 1;
- fp = fopen(infile, "rb");
- if (!fp) {
- fprintf(stderr, "Unable to open %s\n", infile);
- goto done;
- }
- rsa_key = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL);
- if (!rsa_key) {
- /* Check if the PEM contains only a public key */
- if (0 != fseek(fp, 0, SEEK_SET)) {
- fprintf(stderr, "Error seeking in %s\n", infile);
- goto done;
- }
- rsa_key = PEM_read_RSA_PUBKEY(fp, NULL, NULL, NULL);
- }
- fclose(fp);
- if (!rsa_key) {
- fprintf(stderr, "Unable to read RSA key from %s\n", infile);
- goto done;
- }
- /* Public keys doesn't have the private exponent */
- has_priv = !!rsa_key->d;
- if (!has_priv)
- fprintf(stderr, "%s has a public key only.\n", infile);
- sig_alg = vb2_rsa_sig_alg(rsa_key);
- if (sig_alg == VB2_SIG_INVALID) {
- fprintf(stderr, "Unsupported sig algorithm in RSA key\n");
- goto done;
- }
- if (has_priv) {
- /* Create the private key */
- privkey = calloc(1, sizeof(*privkey));
- if (!privkey) {
- fprintf(stderr, "Unable to allocate the private key\n");
- goto done;
- }
- privkey->rsa_private_key = rsa_key;
- privkey->sig_alg = sig_alg;
- privkey->hash_alg = opt_hash_alg;
- if (opt_desc && vb2_private_key_set_desc(privkey, opt_desc)) {
- fprintf(stderr,
- "Unable to set the private key description\n");
- goto done;
- }
- }
- /* Create the public key */
- if (vb2_public_key_alloc(&pubkey, sig_alg)) {
- fprintf(stderr, "Unable to allocate the public key\n");
- goto done;
- }
- /* Extract the keyb blob */
- if (vb_keyb_from_rsa(rsa_key, &keyb_data, &keyb_size)) {
- fprintf(stderr, "Couldn't extract the public key\n");
- goto done;
- }
- /*
- * Copy the keyb blob to the public key's buffer, because that's where
- * vb2_unpack_key_data() and vb2_public_key_pack() expect to find it.
- */
- pubkey_buf = vb2_public_key_packed_data(pubkey);
- memcpy(pubkey_buf, keyb_data, keyb_size);
- /* Fill in the internal struct pointers */
- if (vb2_unpack_key_data(pubkey, pubkey_buf, keyb_size)) {
- fprintf(stderr, "Unable to unpack the public key blob\n");
- goto done;
- }
- pubkey->hash_alg = opt_hash_alg;
- pubkey->version = opt_version;
- if (opt_desc && vb2_public_key_set_desc(pubkey, opt_desc)) {
- fprintf(stderr, "Unable to set pubkey description\n");
- goto done;
- }
- /* Update the IDs */
- if (!force_id) {
- vb2_digest_buffer(keyb_data, keyb_size, VB2_HASH_SHA1,
- opt_id.raw, sizeof(opt_id.raw));
- }
- memcpy((struct vb2_id *)pubkey->id, &opt_id, sizeof(opt_id));
- /* Write them out */
- if (has_priv) {
- privkey->id = opt_id;
- strcpy(outext, ".vbprik2");
- if (vb21_private_key_write(privkey, outfile)) {
- fprintf(stderr, "unable to write private key\n");
- goto done;
- }
- fprintf(stderr, "wrote %s\n", outfile);
- }
- strcpy(outext, ".vbpubk2");
- if (vb21_public_key_write(pubkey, outfile)) {
- fprintf(stderr, "unable to write public key\n");
- goto done;
- }
- fprintf(stderr, "wrote %s\n", outfile);
- ret = 0;
- done:
- RSA_free(rsa_key);
- if (privkey) /* prevent double-free */
- privkey->rsa_private_key = 0;
- vb2_private_key_free(privkey);
- vb2_public_key_free(pubkey);
- free(keyb_data);
- return ret;
- }
- static int do_create(int argc, char *argv[])
- {
- int errorcnt = 0;
- char *e, *s;
- int i, r, len, remove_ext = 0;
- while ((i = getopt_long(argc, argv, "", long_opts, NULL)) != -1) {
- switch (i) {
- case OPT_VERSION:
- opt_version = strtoul(optarg, &e, 0);
- if (!*optarg || (e && *e)) {
- fprintf(stderr,
- "invalid version \"%s\"\n", optarg);
- errorcnt = 1;
- }
- break;
- case OPT_DESC:
- opt_desc = optarg;
- break;
- case OPT_ID:
- if (VB2_SUCCESS != vb2_str_to_id(optarg, &opt_id)) {
- fprintf(stderr, "invalid id \"%s\"\n",
- optarg);
- errorcnt = 1;
- }
- force_id = 1;
- break;
- case OPT_HASH_ALG:
- if (!vb2_lookup_hash_alg(optarg, &opt_hash_alg)) {
- fprintf(stderr,
- "invalid hash_alg \"%s\"\n", optarg);
- errorcnt++;
- }
- break;
- case OPT_HELP:
- print_help(argc, argv);
- return !!errorcnt;
- case '?':
- if (optopt)
- fprintf(stderr, "Unrecognized option: -%c\n",
- optopt);
- else
- fprintf(stderr, "Unrecognized option\n");
- errorcnt++;
- break;
- case ':':
- fprintf(stderr, "Missing argument to -%c\n", optopt);
- errorcnt++;
- break;
- case 0: /* handled option */
- break;
- default:
- DIE;
- }
- }
- /* If we don't have an input file already, we need one */
- if (!infile) {
- if (argc - optind <= 0) {
- fprintf(stderr, "ERROR: missing input filename\n");
- errorcnt++;
- } else {
- infile = argv[optind++];
- }
- }
- if (errorcnt) {
- print_help(argc, argv);
- return 1;
- }
- /* Decide how to determine the output filenames. */
- if (argc > optind) {
- s = argv[optind++]; /* just use this */
- } else {
- s = infile; /* based on pem file name */
- remove_ext = 1;
- }
- /* Make an extra-large copy to leave room for filename extensions */
- len = strlen(s) + 20;
- outfile = (char *)malloc(len);
- if (!outfile) {
- fprintf(stderr, "ERROR: malloc() failed\n");
- return 1;
- }
- strcpy(outfile, s);
- if (remove_ext) {
- /* Find the last '/' if any, then the last '.' before that. */
- s = strrchr(outfile, '/');
- if (!s)
- s = outfile;
- s = strrchr(s, '.');
- /* Cut off the extension */
- if (s)
- *s = '\0';
- }
- /* Remember that spot for later */
- outext = outfile + strlen(outfile);
- /* Okay, do it */
- if (vboot_version == VBOOT_VERSION_1_0)
- r = vb1_make_keypair();
- else
- r = vb2_make_keypair();
- free(outfile);
- return r;
- }
- DECLARE_FUTIL_COMMAND(create, do_create, VBOOT_VERSION_ALL,
- "Create a keypair from an RSA .pem file");
|