cmd_vbutil_keyblock.c 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. /* Copyright (c) 2011 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. * Verified boot key block utility
  6. */
  7. #include <getopt.h>
  8. #include <stdint.h>
  9. #include <stdio.h>
  10. #include <stdlib.h>
  11. #include <string.h>
  12. #include "2sysincludes.h"
  13. #include "2common.h"
  14. #include "2rsa.h"
  15. #include "futility.h"
  16. #include "host_common.h"
  17. #include "host_key2.h"
  18. #include "util_misc.h"
  19. #include "vb1_helper.h"
  20. #include "vb2_common.h"
  21. #include "vboot_common.h"
  22. /* Command line options */
  23. enum {
  24. OPT_MODE_PACK = 1000,
  25. OPT_MODE_UNPACK,
  26. OPT_DATAPUBKEY,
  27. OPT_SIGNPUBKEY,
  28. OPT_SIGNPRIVATE,
  29. OPT_SIGNPRIVATE_PEM,
  30. OPT_PEM_ALGORITHM,
  31. OPT_EXTERNAL_SIGNER,
  32. OPT_FLAGS,
  33. OPT_HELP,
  34. };
  35. static const struct option long_opts[] = {
  36. {"pack", 1, 0, OPT_MODE_PACK},
  37. {"unpack", 1, 0, OPT_MODE_UNPACK},
  38. {"datapubkey", 1, 0, OPT_DATAPUBKEY},
  39. {"signpubkey", 1, 0, OPT_SIGNPUBKEY},
  40. {"signprivate", 1, 0, OPT_SIGNPRIVATE},
  41. {"signprivate_pem", 1, 0, OPT_SIGNPRIVATE_PEM},
  42. {"pem_algorithm", 1, 0, OPT_PEM_ALGORITHM},
  43. {"externalsigner", 1, 0, OPT_EXTERNAL_SIGNER},
  44. {"flags", 1, 0, OPT_FLAGS},
  45. {"help", 0, 0, OPT_HELP},
  46. {NULL, 0, 0, 0}
  47. };
  48. static const char usage[] =
  49. "\n"
  50. "Usage: " MYNAME " %s <--pack|--unpack> <file> [OPTIONS]\n"
  51. "\n"
  52. "For '--pack <file>', required OPTIONS are:\n"
  53. " --datapubkey <file> Data public key in .vbpubk format\n"
  54. "\n"
  55. "Optional OPTIONS are:\n"
  56. " --signprivate <file>"
  57. " Signing private key in .vbprivk format.\n"
  58. "OR\n"
  59. " --signprivate_pem <file>\n"
  60. " --pem_algorithm <algo>\n"
  61. " Signing private key in .pem format and algorithm id.\n"
  62. "(If one of the above arguments is not specified, the keyblock will\n"
  63. "not be signed.)\n"
  64. "\n"
  65. " --flags <number> Specifies allowed use conditions.\n"
  66. " --externalsigner \"cmd\""
  67. " Use an external program cmd to calculate the signatures.\n"
  68. "\n"
  69. "For '--unpack <file>', optional OPTIONS are:\n"
  70. " --signpubkey <file>"
  71. " Signing public key in .vbpubk format. This is required to\n"
  72. " verify a signed keyblock.\n"
  73. " --datapubkey <file>"
  74. " Write the data public key to this file.\n\n";
  75. static void print_help(int argc, char *argv[])
  76. {
  77. printf(usage, argv[0]);
  78. }
  79. /* Pack a .keyblock */
  80. static int Pack(const char *outfile, const char *datapubkey,
  81. const char *signprivate,
  82. const char *signprivate_pem, uint64_t pem_algorithm,
  83. uint64_t flags, const char *external_signer)
  84. {
  85. struct vb2_private_key *signing_key = NULL;
  86. struct vb2_keyblock *block;
  87. if (!outfile) {
  88. fprintf(stderr,
  89. "vbutil_keyblock: Must specify output filename.\n");
  90. return 1;
  91. }
  92. if (!datapubkey) {
  93. fprintf(stderr,
  94. "vbutil_keyblock: Must specify data public key.\n");
  95. return 1;
  96. }
  97. struct vb2_packed_key *data_key = vb2_read_packed_key(datapubkey);
  98. if (!data_key) {
  99. fprintf(stderr, "vbutil_keyblock: Error reading data key.\n");
  100. return 1;
  101. }
  102. if (signprivate_pem) {
  103. if (pem_algorithm >= VB2_ALG_COUNT) {
  104. fprintf(stderr,
  105. "vbutil_keyblock: Invalid --pem_algorithm %"
  106. PRIu64 "\n", pem_algorithm);
  107. return 1;
  108. }
  109. if (external_signer) {
  110. /* External signing uses the PEM file directly. */
  111. block = vb2_create_keyblock_external(data_key,
  112. signprivate_pem,
  113. pem_algorithm,
  114. flags,
  115. external_signer);
  116. } else {
  117. signing_key =
  118. vb2_read_private_key_pem(signprivate_pem,
  119. pem_algorithm);
  120. if (!signing_key) {
  121. fprintf(stderr, "vbutil_keyblock:"
  122. " Error reading signing key.\n");
  123. return 1;
  124. }
  125. block = vb2_create_keyblock(data_key, signing_key,
  126. flags);
  127. }
  128. } else {
  129. if (signprivate) {
  130. signing_key = vb2_read_private_key(signprivate);
  131. if (!signing_key) {
  132. fprintf(stderr, "vbutil_keyblock:"
  133. " Error reading signing key.\n");
  134. return 1;
  135. }
  136. }
  137. block = vb2_create_keyblock(data_key, signing_key, flags);
  138. }
  139. free(data_key);
  140. if (signing_key)
  141. free(signing_key);
  142. if (VB2_SUCCESS != vb2_write_keyblock(outfile, block)) {
  143. fprintf(stderr, "vbutil_keyblock: Error writing key block.\n");
  144. return 1;
  145. }
  146. free(block);
  147. return 0;
  148. }
  149. static int Unpack(const char *infile, const char *datapubkey,
  150. const char *signpubkey)
  151. {
  152. struct vb2_packed_key *sign_key = NULL;
  153. if (!infile) {
  154. fprintf(stderr, "vbutil_keyblock: Must specify filename\n");
  155. return 1;
  156. }
  157. struct vb2_keyblock *block = vb2_read_keyblock(infile);
  158. if (!block) {
  159. fprintf(stderr, "vbutil_keyblock: Error reading key block.\n");
  160. return 1;
  161. }
  162. /* If the block is signed, then verify it with the signing public key,
  163. * since vb2_read_keyblock() only verified the hash. */
  164. if (block->keyblock_signature.sig_size && signpubkey) {
  165. static uint8_t workbuf[VB2_WORKBUF_RECOMMENDED_SIZE];
  166. static struct vb2_workbuf wb;
  167. vb2_workbuf_init(&wb, workbuf, sizeof(workbuf));
  168. sign_key = vb2_read_packed_key(signpubkey);
  169. if (!sign_key) {
  170. fprintf(stderr,
  171. "vbutil_keyblock: Error reading signpubkey.\n");
  172. return 1;
  173. }
  174. struct vb2_public_key key;
  175. if (VB2_SUCCESS != vb2_unpack_key(&key, sign_key)) {
  176. fprintf(stderr,
  177. "vbutil_keyblock: Error reading signpubkey.\n");
  178. return 1;
  179. }
  180. if (VB2_SUCCESS !=
  181. vb2_verify_keyblock(block, block->keyblock_size,
  182. &key, &wb)) {
  183. fprintf(stderr, "vbutil_keyblock:"
  184. " Error verifying key block.\n");
  185. return 1;
  186. }
  187. free(sign_key);
  188. }
  189. printf("Key block file: %s\n", infile);
  190. printf("Signature %s\n", sign_key ? "valid" : "ignored");
  191. printf("Flags: %u ", block->keyblock_flags);
  192. if (block->keyblock_flags & KEY_BLOCK_FLAG_DEVELOPER_0)
  193. printf(" !DEV");
  194. if (block->keyblock_flags & KEY_BLOCK_FLAG_DEVELOPER_1)
  195. printf(" DEV");
  196. if (block->keyblock_flags & KEY_BLOCK_FLAG_RECOVERY_0)
  197. printf(" !REC");
  198. if (block->keyblock_flags & KEY_BLOCK_FLAG_RECOVERY_1)
  199. printf(" REC");
  200. printf("\n");
  201. struct vb2_packed_key *data_key = &block->data_key;
  202. printf("Data key algorithm: %u %s\n", data_key->algorithm,
  203. vb2_get_crypto_algorithm_name(data_key->algorithm));
  204. printf("Data key version: %u\n", data_key->key_version);
  205. printf("Data key sha1sum: %s\n",
  206. packed_key_sha1_string(data_key));
  207. if (datapubkey &&
  208. VB2_SUCCESS != vb2_write_packed_key(datapubkey, data_key)) {
  209. fprintf(stderr, "vbutil_keyblock: error writing public key\n");
  210. return 1;
  211. }
  212. free(block);
  213. return 0;
  214. }
  215. static int do_vbutil_keyblock(int argc, char *argv[])
  216. {
  217. char *filename = NULL;
  218. char *datapubkey = NULL;
  219. char *signpubkey = NULL;
  220. char *signprivate = NULL;
  221. char *signprivate_pem = NULL;
  222. char *external_signer = NULL;
  223. uint64_t flags = 0;
  224. uint64_t pem_algorithm = 0;
  225. int is_pem_algorithm = 0;
  226. int mode = 0;
  227. int parse_error = 0;
  228. char *e;
  229. int i;
  230. while ((i = getopt_long(argc, argv, "", long_opts, NULL)) != -1) {
  231. switch (i) {
  232. case '?':
  233. /* Unhandled option */
  234. printf("Unknown option\n");
  235. parse_error = 1;
  236. break;
  237. case OPT_HELP:
  238. print_help(argc, argv);
  239. return !!parse_error;
  240. case OPT_MODE_PACK:
  241. case OPT_MODE_UNPACK:
  242. mode = i;
  243. filename = optarg;
  244. break;
  245. case OPT_DATAPUBKEY:
  246. datapubkey = optarg;
  247. break;
  248. case OPT_SIGNPUBKEY:
  249. signpubkey = optarg;
  250. break;
  251. case OPT_SIGNPRIVATE:
  252. signprivate = optarg;
  253. break;
  254. case OPT_SIGNPRIVATE_PEM:
  255. signprivate_pem = optarg;
  256. break;
  257. case OPT_PEM_ALGORITHM:
  258. pem_algorithm = strtoul(optarg, &e, 0);
  259. if (!*optarg || (e && *e)) {
  260. fprintf(stderr, "Invalid --pem_algorithm\n");
  261. parse_error = 1;
  262. } else {
  263. is_pem_algorithm = 1;
  264. }
  265. break;
  266. case OPT_EXTERNAL_SIGNER:
  267. external_signer = optarg;
  268. break;
  269. case OPT_FLAGS:
  270. flags = strtoul(optarg, &e, 0);
  271. if (!*optarg || (e && *e)) {
  272. fprintf(stderr, "Invalid --flags\n");
  273. parse_error = 1;
  274. }
  275. break;
  276. }
  277. }
  278. /* Check if the right combination of options was provided. */
  279. if (signprivate && signprivate_pem) {
  280. fprintf(stderr,
  281. "Only one of --signprivate or --signprivate_pem must"
  282. " be specified\n");
  283. parse_error = 1;
  284. }
  285. if (signprivate_pem && !is_pem_algorithm) {
  286. fprintf(stderr, "--pem_algorithm must be used with"
  287. " --signprivate_pem\n");
  288. parse_error = 1;
  289. }
  290. if (external_signer && !signprivate_pem) {
  291. fprintf(stderr,
  292. "--externalsigner must be used with --signprivate_pem"
  293. "\n");
  294. parse_error = 1;
  295. }
  296. if (parse_error) {
  297. print_help(argc, argv);
  298. return 1;
  299. }
  300. switch (mode) {
  301. case OPT_MODE_PACK:
  302. return Pack(filename, datapubkey, signprivate,
  303. signprivate_pem, pem_algorithm,
  304. flags, external_signer);
  305. case OPT_MODE_UNPACK:
  306. return Unpack(filename, datapubkey, signpubkey);
  307. default:
  308. printf("Must specify a mode.\n");
  309. print_help(argc, argv);
  310. return 1;
  311. }
  312. }
  313. DECLARE_FUTIL_COMMAND(vbutil_keyblock, do_vbutil_keyblock, VBOOT_VERSION_1_0,
  314. "Creates, signs, and verifies a keyblock");