cmd_create.c 9.5 KB

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