grub-protect.c 35 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408
  1. /*
  2. * GRUB -- GRand Unified Bootloader
  3. * Copyright (C) 2022 Microsoft Corporation
  4. * Copyright (C) 2023 SUSE LLC
  5. * Copyright (C) 2024 Free Software Foundation, Inc.
  6. *
  7. * GRUB is free software: you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation, either version 3 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * GRUB is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
  19. */
  20. #include <config.h>
  21. #include <errno.h>
  22. #include <fcntl.h>
  23. #include <libtasn1.h>
  24. #include <stdio.h>
  25. #include <string.h>
  26. #include <unistd.h>
  27. #include <grub/emu/hostdisk.h>
  28. #include <grub/emu/misc.h>
  29. #include <grub/util/misc.h>
  30. #include <tss2_buffer.h>
  31. #include <tss2_mu.h>
  32. #include <tcg2.h>
  33. #include <tpm2_args.h>
  34. #include <tpm2.h>
  35. #pragma GCC diagnostic ignored "-Wmissing-prototypes"
  36. #pragma GCC diagnostic ignored "-Wmissing-declarations"
  37. #include <argp.h>
  38. #pragma GCC diagnostic error "-Wmissing-prototypes"
  39. #pragma GCC diagnostic error "-Wmissing-declarations"
  40. #include "progname.h"
  41. /* Unprintable option keys for argp */
  42. typedef enum protect_opt
  43. {
  44. /* General */
  45. PROTECT_OPT_ACTION = 'a',
  46. PROTECT_OPT_PROTECTOR = 'p',
  47. /* TPM2 */
  48. PROTECT_OPT_TPM2_DEVICE = 0x100,
  49. PROTECT_OPT_TPM2_PCRS,
  50. PROTECT_OPT_TPM2_ASYMMETRIC,
  51. PROTECT_OPT_TPM2_BANK,
  52. PROTECT_OPT_TPM2_SRK,
  53. PROTECT_OPT_TPM2_KEYFILE,
  54. PROTECT_OPT_TPM2_OUTFILE,
  55. PROTECT_OPT_TPM2_EVICT,
  56. PROTECT_OPT_TPM2_TPM2KEY
  57. } protect_opt_t;
  58. /* Option flags to keep track of specified arguments */
  59. typedef enum protect_arg
  60. {
  61. /* General */
  62. PROTECT_ARG_ACTION = 1 << 0,
  63. PROTECT_ARG_PROTECTOR = 1 << 1,
  64. /* TPM2 */
  65. PROTECT_ARG_TPM2_DEVICE = 1 << 2,
  66. PROTECT_ARG_TPM2_PCRS = 1 << 3,
  67. PROTECT_ARG_TPM2_ASYMMETRIC = 1 << 4,
  68. PROTECT_ARG_TPM2_BANK = 1 << 5,
  69. PROTECT_ARG_TPM2_SRK = 1 << 6,
  70. PROTECT_ARG_TPM2_KEYFILE = 1 << 7,
  71. PROTECT_ARG_TPM2_OUTFILE = 1 << 8,
  72. PROTECT_ARG_TPM2_EVICT = 1 << 9,
  73. PROTECT_ARG_TPM2_TPM2KEY = 1 << 10
  74. } protect_arg_t;
  75. typedef enum protect_protector
  76. {
  77. PROTECT_TYPE_ERROR,
  78. PROTECT_TYPE_TPM2
  79. } protect_protector_t;
  80. typedef enum protect_action
  81. {
  82. PROTECT_ACTION_ERROR,
  83. PROTECT_ACTION_ADD,
  84. PROTECT_ACTION_REMOVE
  85. } protect_action_t;
  86. typedef struct protect_args
  87. {
  88. protect_arg_t args;
  89. protect_action_t action;
  90. protect_protector_t protector;
  91. const char *tpm2_device;
  92. grub_uint8_t tpm2_pcrs[TPM_MAX_PCRS];
  93. grub_uint8_t tpm2_pcr_count;
  94. grub_srk_type_t srk_type;
  95. TPM_ALG_ID_t tpm2_bank;
  96. TPM_HANDLE_t tpm2_srk;
  97. const char *tpm2_keyfile;
  98. const char *tpm2_outfile;
  99. bool tpm2_evict;
  100. bool tpm2_tpm2key;
  101. } protect_args_t;
  102. static struct argp_option protect_options[] =
  103. {
  104. /* Top-level options */
  105. {
  106. .name = "action",
  107. .key = 'a',
  108. .arg = "add|remove",
  109. .flags = 0,
  110. .doc =
  111. N_("Add or remove a key protector to or from a key."),
  112. .group = 0
  113. },
  114. {
  115. .name = "protector",
  116. .key = 'p',
  117. .arg = "tpm2",
  118. .flags = 0,
  119. .doc =
  120. N_("Set key protector to use (only tpm2 is currently supported)."),
  121. .group = 0
  122. },
  123. /* TPM2 key protector options */
  124. {
  125. .name = "tpm2-device",
  126. .key = PROTECT_OPT_TPM2_DEVICE,
  127. .arg = "FILE",
  128. .flags = 0,
  129. .doc =
  130. N_("Set the path to the TPM2 device. (default: /dev/tpm0)"),
  131. .group = 0
  132. },
  133. {
  134. .name = "tpm2-pcrs",
  135. .key = PROTECT_OPT_TPM2_PCRS,
  136. .arg = "0[,1]...",
  137. .flags = 0,
  138. .doc =
  139. N_("Set a comma-separated list of PCRs used to authorize key release "
  140. "e.g., '7,11'. Please be aware that PCR 0~7 are used by the "
  141. "firmware and the measurement result may change after a "
  142. "firmware update (for baremetal systems) or a package "
  143. "(OVMF/SLOF) update in the VM host. This may lead to "
  144. "the failure of key unsealing. (default: 7)"),
  145. .group = 0
  146. },
  147. {
  148. .name = "tpm2-bank",
  149. .key = PROTECT_OPT_TPM2_BANK,
  150. .arg = "ALG",
  151. .flags = 0,
  152. .doc =
  153. N_("Set the bank of PCRs used to authorize key release: "
  154. "SHA1, SHA256, SHA384, or SHA512. (default: SHA256)"),
  155. .group = 0
  156. },
  157. {
  158. .name = "tpm2-keyfile",
  159. .key = PROTECT_OPT_TPM2_KEYFILE,
  160. .arg = "FILE",
  161. .flags = 0,
  162. .doc =
  163. N_("Set the path to a file that contains the cleartext key to protect."),
  164. .group = 0
  165. },
  166. {
  167. .name = "tpm2-outfile",
  168. .key = PROTECT_OPT_TPM2_OUTFILE,
  169. .arg = "FILE",
  170. .flags = 0,
  171. .doc =
  172. N_("Set the path to the file that will contain the key after sealing "
  173. "(must be accessible to GRUB during boot)."),
  174. .group = 0
  175. },
  176. {
  177. .name = "tpm2-srk",
  178. .key = PROTECT_OPT_TPM2_SRK,
  179. .arg = "NUM",
  180. .flags = 0,
  181. .doc =
  182. N_("Set the SRK handle if the SRK is to be made persistent."),
  183. .group = 0
  184. },
  185. {
  186. .name = "tpm2-asymmetric",
  187. .key = PROTECT_OPT_TPM2_ASYMMETRIC,
  188. .arg = "TYPE",
  189. .flags = 0,
  190. .doc =
  191. N_("Set the type of SRK: RSA (RSA2048) and ECC (ECC_NIST_P256)."
  192. "(default: ECC)"),
  193. .group = 0
  194. },
  195. {
  196. .name = "tpm2-evict",
  197. .key = PROTECT_OPT_TPM2_EVICT,
  198. .arg = NULL,
  199. .flags = 0,
  200. .doc =
  201. N_("Evict a previously persisted SRK from the TPM, if any."),
  202. .group = 0
  203. },
  204. {
  205. .name = "tpm2key",
  206. .key = PROTECT_OPT_TPM2_TPM2KEY,
  207. .arg = NULL,
  208. .flags = 0,
  209. .doc =
  210. N_("Use TPM 2.0 Key File format."),
  211. .group = 0
  212. },
  213. /* End of list */
  214. { 0, 0, 0, 0, 0, 0 }
  215. };
  216. static int protector_tpm2_fd = -1;
  217. static grub_err_t
  218. protect_read_file (const char *filepath, void **buffer, size_t *buffer_size)
  219. {
  220. grub_err_t err;
  221. FILE *f;
  222. long len;
  223. void *buf;
  224. f = fopen (filepath, "rb");
  225. if (f == NULL)
  226. {
  227. fprintf (stderr, N_("Could not open file: %s\n"), filepath);
  228. return GRUB_ERR_FILE_NOT_FOUND;
  229. }
  230. if (fseek (f, 0, SEEK_END))
  231. {
  232. fprintf (stderr, N_("Could not seek file: %s\n"), filepath);
  233. err = GRUB_ERR_FILE_READ_ERROR;
  234. goto exit1;
  235. }
  236. len = ftell (f);
  237. if (len <= 0)
  238. {
  239. fprintf (stderr, N_("Could not get file length: %s\n"), filepath);
  240. err = GRUB_ERR_FILE_READ_ERROR;
  241. goto exit1;
  242. }
  243. rewind (f);
  244. buf = grub_malloc (len);
  245. if (buf == NULL)
  246. {
  247. fprintf (stderr, N_("Could not allocate memory for file: %s\n"), filepath);
  248. err = GRUB_ERR_OUT_OF_MEMORY;
  249. goto exit1;
  250. }
  251. if (fread (buf, len, 1, f) != 1)
  252. {
  253. fprintf (stderr, N_("Could not read file: %s\n"), filepath);
  254. err = GRUB_ERR_FILE_READ_ERROR;
  255. goto exit2;
  256. }
  257. *buffer = buf;
  258. *buffer_size = len;
  259. buf = NULL;
  260. err = GRUB_ERR_NONE;
  261. exit2:
  262. grub_free (buf);
  263. exit1:
  264. fclose (f);
  265. return err;
  266. }
  267. static grub_err_t
  268. protect_write_file (const char *filepath, void *buffer, size_t buffer_size)
  269. {
  270. grub_err_t err;
  271. FILE *f;
  272. f = fopen (filepath, "wb");
  273. if (f == NULL)
  274. return GRUB_ERR_FILE_NOT_FOUND;
  275. if (fwrite (buffer, buffer_size, 1, f) != 1)
  276. {
  277. err = GRUB_ERR_WRITE_ERROR;
  278. goto exit;
  279. }
  280. err = GRUB_ERR_NONE;
  281. exit:
  282. fclose (f);
  283. return err;
  284. }
  285. grub_err_t
  286. grub_tcg2_get_max_output_size (grub_size_t *size)
  287. {
  288. if (size == NULL)
  289. return GRUB_ERR_BAD_ARGUMENT;
  290. *size = GRUB_TPM2_BUFFER_CAPACITY;
  291. return GRUB_ERR_NONE;
  292. }
  293. grub_err_t
  294. grub_tcg2_submit_command (grub_size_t input_size, grub_uint8_t *input,
  295. grub_size_t output_size, grub_uint8_t *output)
  296. {
  297. if (write (protector_tpm2_fd, input, input_size) != input_size)
  298. {
  299. fprintf (stderr, N_("Could not send TPM command.\n"));
  300. return GRUB_ERR_BAD_DEVICE;
  301. }
  302. if (read (protector_tpm2_fd, output, output_size) < sizeof (TPM_RESPONSE_HEADER_t))
  303. {
  304. fprintf (stderr, N_("Could not get TPM response.\n"));
  305. return GRUB_ERR_BAD_DEVICE;
  306. }
  307. return GRUB_ERR_NONE;
  308. }
  309. static grub_err_t
  310. protect_tpm2_open_device (const char *dev_node)
  311. {
  312. if (protector_tpm2_fd != -1)
  313. return GRUB_ERR_NONE;
  314. protector_tpm2_fd = open (dev_node, O_RDWR);
  315. if (protector_tpm2_fd == -1)
  316. {
  317. fprintf (stderr, N_("Could not open TPM device (%s).\n"), strerror (errno));
  318. return GRUB_ERR_FILE_NOT_FOUND;
  319. }
  320. return GRUB_ERR_NONE;
  321. }
  322. static grub_err_t
  323. protect_tpm2_close_device (void)
  324. {
  325. int err;
  326. if (protector_tpm2_fd == -1)
  327. return GRUB_ERR_NONE;
  328. err = close (protector_tpm2_fd);
  329. if (err != GRUB_ERR_NONE)
  330. {
  331. fprintf (stderr, N_("Could not close TPM device (%s).\n"), strerror (errno));
  332. return GRUB_ERR_IO;
  333. }
  334. protector_tpm2_fd = -1;
  335. return GRUB_ERR_NONE;
  336. }
  337. static grub_err_t
  338. protect_tpm2_get_policy_digest (protect_args_t *args, TPM2B_DIGEST_t *digest)
  339. {
  340. TPM_RC_t rc;
  341. TPML_PCR_SELECTION_t pcr_sel = {
  342. .count = 1,
  343. .pcrSelections = {
  344. {
  345. .hash = args->tpm2_bank,
  346. .sizeOfSelect = 3,
  347. .pcrSelect = {0}
  348. },
  349. }
  350. };
  351. TPML_PCR_SELECTION_t pcr_sel_out = {0};
  352. TPML_DIGEST_t pcr_values = {0};
  353. TPM2B_DIGEST_t pcr_digest = {0};
  354. grub_size_t pcr_digest_len;
  355. TPM2B_MAX_BUFFER_t pcr_concat = {0};
  356. grub_size_t pcr_concat_len;
  357. grub_uint8_t *pcr_cursor;
  358. TPM2B_NONCE_t nonce = {0};
  359. TPM2B_ENCRYPTED_SECRET_t salt = {0};
  360. TPMT_SYM_DEF_t symmetric = {0};
  361. TPMI_SH_AUTH_SESSION_t session = 0;
  362. TPM2B_DIGEST_t policy_digest = {0};
  363. grub_uint8_t i;
  364. grub_err_t err;
  365. /* PCR Read */
  366. for (i = 0; i < args->tpm2_pcr_count; i++)
  367. TPMS_PCR_SELECTION_SelectPCR (&pcr_sel.pcrSelections[0], args->tpm2_pcrs[i]);
  368. rc = grub_tpm2_pcr_read (NULL, &pcr_sel, NULL, &pcr_sel_out, &pcr_values, NULL);
  369. if (rc != TPM_RC_SUCCESS)
  370. {
  371. fprintf (stderr, "Failed to read PCRs (TPM2_PCR_Read: 0x%x).\n", rc);
  372. return GRUB_ERR_BAD_DEVICE;
  373. }
  374. if ((pcr_sel_out.count != pcr_sel.count) ||
  375. (pcr_sel.pcrSelections[0].sizeOfSelect !=
  376. pcr_sel_out.pcrSelections[0].sizeOfSelect))
  377. {
  378. fprintf (stderr, N_("Could not read all the specified PCRs.\n"));
  379. return GRUB_ERR_BAD_DEVICE;
  380. }
  381. /* Compute PCR Digest */
  382. switch (args->tpm2_bank)
  383. {
  384. case TPM_ALG_SHA1:
  385. pcr_digest_len = TPM_SHA1_DIGEST_SIZE;
  386. break;
  387. case TPM_ALG_SHA256:
  388. pcr_digest_len = TPM_SHA256_DIGEST_SIZE;
  389. break;
  390. case TPM_ALG_SHA384:
  391. pcr_digest_len = TPM_SHA384_DIGEST_SIZE;
  392. break;
  393. case TPM_ALG_SHA512:
  394. pcr_digest_len = TPM_SHA512_DIGEST_SIZE;
  395. break;
  396. default:
  397. return GRUB_ERR_BAD_ARGUMENT;
  398. }
  399. pcr_concat_len = pcr_digest_len * args->tpm2_pcr_count;
  400. if (pcr_concat_len > TPM_MAX_DIGEST_BUFFER)
  401. {
  402. fprintf (stderr, N_("PCR concatenation buffer not big enough.\n"));
  403. return GRUB_ERR_OUT_OF_RANGE;
  404. }
  405. pcr_cursor = pcr_concat.buffer;
  406. for (i = 0; i < args->tpm2_pcr_count; i++)
  407. {
  408. if (pcr_values.digests[i].size != pcr_digest_len)
  409. {
  410. fprintf (stderr,
  411. N_("Bad PCR value size: expected %llu bytes but got %u bytes.\n"),
  412. (long long unsigned int)pcr_digest_len, pcr_values.digests[i].size);
  413. return GRUB_ERR_BAD_ARGUMENT;
  414. }
  415. grub_memcpy (pcr_cursor, pcr_values.digests[i].buffer, pcr_digest_len);
  416. pcr_cursor += pcr_digest_len;
  417. }
  418. pcr_concat.size = pcr_concat_len;
  419. rc = grub_tpm2_hash (NULL, &pcr_concat, args->tpm2_bank, TPM_RH_NULL, &pcr_digest, NULL, NULL);
  420. if (rc != TPM_RC_SUCCESS)
  421. {
  422. fprintf (stderr, "Failed to generate PCR digest (TPM2_Hash: 0x%x)\n", rc);
  423. return GRUB_ERR_BAD_DEVICE;
  424. }
  425. /* Start Trial Session */
  426. nonce.size = TPM_SHA256_DIGEST_SIZE;
  427. symmetric.algorithm = TPM_ALG_NULL;
  428. rc = grub_tpm2_startauthsession (TPM_RH_NULL, TPM_RH_NULL, 0, &nonce, &salt,
  429. TPM_SE_TRIAL, &symmetric, TPM_ALG_SHA256,
  430. &session, NULL, 0);
  431. if (rc != TPM_RC_SUCCESS)
  432. {
  433. fprintf (stderr, "Failed to start trial policy session (TPM2_StartAuthSession: 0x%x).\n", rc);
  434. return GRUB_ERR_BAD_DEVICE;
  435. }
  436. /* PCR Policy */
  437. rc = grub_tpm2_policypcr (session, NULL, &pcr_digest, &pcr_sel, NULL);
  438. if (rc != TPM_RC_SUCCESS)
  439. {
  440. fprintf (stderr, "Failed to submit PCR policy (TPM2_PolicyPCR: 0x%x).\n", rc);
  441. err = GRUB_ERR_BAD_DEVICE;
  442. goto error;
  443. }
  444. /* Retrieve Policy Digest */
  445. rc = grub_tpm2_policygetdigest (session, NULL, &policy_digest, NULL);
  446. if (rc != TPM_RC_SUCCESS)
  447. {
  448. fprintf (stderr, "Failed to get policy digest (TPM2_PolicyGetDigest: 0x%x).\n", rc);
  449. err = GRUB_ERR_BAD_DEVICE;
  450. goto error;
  451. }
  452. /* Epilogue */
  453. *digest = policy_digest;
  454. err = GRUB_ERR_NONE;
  455. error:
  456. grub_tpm2_flushcontext (session);
  457. return err;
  458. }
  459. static grub_err_t
  460. protect_tpm2_get_srk (protect_args_t *args, TPM_HANDLE_t *srk)
  461. {
  462. TPM_RC_t rc;
  463. TPM2B_PUBLIC_t public;
  464. TPMS_AUTH_COMMAND_t authCommand = {0};
  465. TPM2B_SENSITIVE_CREATE_t inSensitive = {0};
  466. TPM2B_PUBLIC_t inPublic = {0};
  467. TPM2B_DATA_t outsideInfo = {0};
  468. TPML_PCR_SELECTION_t creationPcr = {0};
  469. TPM2B_PUBLIC_t outPublic = {0};
  470. TPM2B_CREATION_DATA_t creationData = {0};
  471. TPM2B_DIGEST_t creationHash = {0};
  472. TPMT_TK_CREATION_t creationTicket = {0};
  473. TPM2B_NAME_t srkName = {0};
  474. TPM_HANDLE_t srkHandle;
  475. if (args->tpm2_srk != 0)
  476. {
  477. /* Find SRK */
  478. rc = grub_tpm2_readpublic (args->tpm2_srk, NULL, &public);
  479. if (rc == TPM_RC_SUCCESS)
  480. {
  481. printf ("Read SRK from 0x%x\n", args->tpm2_srk);
  482. *srk = args->tpm2_srk;
  483. return GRUB_ERR_NONE;
  484. }
  485. /* The handle exists but its public area could not be read. */
  486. if ((rc & ~TPM_RC_N_MASK) != TPM_RC_HANDLE)
  487. {
  488. fprintf (stderr, "Failed to retrieve SRK from 0x%x (TPM2_ReadPublic: 0x%x).\n", args->tpm2_srk, rc);
  489. return GRUB_ERR_BAD_DEVICE;
  490. }
  491. }
  492. /* Create SRK */
  493. authCommand.sessionHandle = TPM_RS_PW;
  494. inPublic.publicArea.type = args->srk_type.type;
  495. inPublic.publicArea.nameAlg = TPM_ALG_SHA256;
  496. inPublic.publicArea.objectAttributes.restricted = 1;
  497. inPublic.publicArea.objectAttributes.userWithAuth = 1;
  498. inPublic.publicArea.objectAttributes.decrypt = 1;
  499. inPublic.publicArea.objectAttributes.fixedTPM = 1;
  500. inPublic.publicArea.objectAttributes.fixedParent = 1;
  501. inPublic.publicArea.objectAttributes.sensitiveDataOrigin = 1;
  502. inPublic.publicArea.objectAttributes.noDA = 1;
  503. switch (args->srk_type.type)
  504. {
  505. case TPM_ALG_RSA:
  506. inPublic.publicArea.parameters.rsaDetail.symmetric.algorithm = TPM_ALG_AES;
  507. inPublic.publicArea.parameters.rsaDetail.symmetric.keyBits.aes = 128;
  508. inPublic.publicArea.parameters.rsaDetail.symmetric.mode.aes = TPM_ALG_CFB;
  509. inPublic.publicArea.parameters.rsaDetail.scheme.scheme = TPM_ALG_NULL;
  510. inPublic.publicArea.parameters.rsaDetail.keyBits = args->srk_type.detail.rsa_bits;
  511. inPublic.publicArea.parameters.rsaDetail.exponent = 0;
  512. break;
  513. case TPM_ALG_ECC:
  514. inPublic.publicArea.parameters.eccDetail.symmetric.algorithm = TPM_ALG_AES;
  515. inPublic.publicArea.parameters.eccDetail.symmetric.keyBits.aes = 128;
  516. inPublic.publicArea.parameters.eccDetail.symmetric.mode.aes = TPM_ALG_CFB;
  517. inPublic.publicArea.parameters.eccDetail.scheme.scheme = TPM_ALG_NULL;
  518. inPublic.publicArea.parameters.eccDetail.curveID = args->srk_type.detail.ecc_curve;
  519. inPublic.publicArea.parameters.eccDetail.kdf.scheme = TPM_ALG_NULL;
  520. break;
  521. default:
  522. return GRUB_ERR_BAD_ARGUMENT;
  523. }
  524. rc = grub_tpm2_createprimary (TPM_RH_OWNER, &authCommand, &inSensitive, &inPublic,
  525. &outsideInfo, &creationPcr, &srkHandle, &outPublic,
  526. &creationData, &creationHash, &creationTicket,
  527. &srkName, NULL);
  528. if (rc != TPM_RC_SUCCESS)
  529. {
  530. fprintf (stderr, "Failed to create SRK (TPM2_CreatePrimary: 0x%x).\n", rc);
  531. return GRUB_ERR_BAD_DEVICE;
  532. }
  533. /* Persist SRK */
  534. if (args->tpm2_srk != 0)
  535. {
  536. rc = grub_tpm2_evictcontrol (TPM_RH_OWNER, srkHandle, &authCommand, args->tpm2_srk, NULL);
  537. if (rc == TPM_RC_SUCCESS)
  538. {
  539. grub_tpm2_flushcontext (srkHandle);
  540. srkHandle = args->tpm2_srk;
  541. }
  542. else
  543. fprintf (stderr,
  544. "Warning: Failed to persist SRK (0x%x) (TPM2_EvictControl: 0x%x).\n"
  545. "Continuing anyway...\n", args->tpm2_srk, rc);
  546. }
  547. /* Epilogue */
  548. *srk = srkHandle;
  549. return GRUB_ERR_NONE;
  550. }
  551. static grub_err_t
  552. protect_tpm2_seal (TPM2B_DIGEST_t *policyDigest, TPM_HANDLE_t srk,
  553. grub_uint8_t *clearText, grub_size_t clearTextLength,
  554. tpm2_sealed_key_t *sealed_key)
  555. {
  556. TPM_RC_t rc;
  557. TPMS_AUTH_COMMAND_t authCommand = {0};
  558. TPM2B_SENSITIVE_CREATE_t inSensitive = {0};
  559. TPM2B_PUBLIC_t inPublic = {0};
  560. TPM2B_DATA_t outsideInfo = {0};
  561. TPML_PCR_SELECTION_t pcr_sel = {0};
  562. TPM2B_PRIVATE_t outPrivate = {0};
  563. TPM2B_PUBLIC_t outPublic = {0};
  564. /* Seal Data */
  565. authCommand.sessionHandle = TPM_RS_PW;
  566. inSensitive.sensitive.data.size = clearTextLength;
  567. memcpy(inSensitive.sensitive.data.buffer, clearText, clearTextLength);
  568. inPublic.publicArea.type = TPM_ALG_KEYEDHASH;
  569. inPublic.publicArea.nameAlg = TPM_ALG_SHA256;
  570. inPublic.publicArea.parameters.keyedHashDetail.scheme.scheme = TPM_ALG_NULL;
  571. inPublic.publicArea.authPolicy = *policyDigest;
  572. rc = grub_tpm2_create (srk, &authCommand, &inSensitive, &inPublic, &outsideInfo,
  573. &pcr_sel, &outPrivate, &outPublic, NULL, NULL, NULL, NULL);
  574. if (rc != TPM_RC_SUCCESS)
  575. {
  576. fprintf (stderr, "Failed to seal key (TPM2_Create: 0x%x).\n", rc);
  577. return GRUB_ERR_BAD_DEVICE;
  578. }
  579. /* Epilogue */
  580. sealed_key->public = outPublic;
  581. sealed_key->private = outPrivate;
  582. return GRUB_ERR_NONE;
  583. }
  584. extern asn1_static_node tpm2key_asn1_tab[];
  585. /* id-sealedkey OID defined in TPM 2.0 Key Files Spec */
  586. #define TPM2KEY_SEALED_KEY_OID "2.23.133.10.1.5"
  587. static grub_err_t
  588. protect_tpm2_export_tpm2key (const protect_args_t *args,
  589. tpm2_sealed_key_t *sealed_key)
  590. {
  591. const char *sealed_key_oid = TPM2KEY_SEALED_KEY_OID;
  592. asn1_node asn1_def = NULL;
  593. asn1_node tpm2key = NULL;
  594. grub_uint32_t parent;
  595. grub_uint32_t cmd_code;
  596. struct grub_tpm2_buffer pol_buf;
  597. TPML_PCR_SELECTION_t pcr_sel = {
  598. .count = 1,
  599. .pcrSelections = {
  600. {
  601. .hash = args->tpm2_bank,
  602. .sizeOfSelect = 3,
  603. .pcrSelect = {0}
  604. },
  605. }
  606. };
  607. struct grub_tpm2_buffer pub_buf;
  608. struct grub_tpm2_buffer priv_buf;
  609. void *der_buf = NULL;
  610. int der_buf_size = 0;
  611. int i;
  612. int ret;
  613. grub_err_t err;
  614. for (i = 0; i < args->tpm2_pcr_count; i++)
  615. TPMS_PCR_SELECTION_SelectPCR (&pcr_sel.pcrSelections[0], args->tpm2_pcrs[i]);
  616. /*
  617. * Prepare the parameters for TPM_CC_PolicyPCR:
  618. * empty pcrDigest and the user selected PCRs
  619. */
  620. grub_tpm2_buffer_init (&pol_buf);
  621. grub_tpm2_buffer_pack_u16 (&pol_buf, 0);
  622. grub_Tss2_MU_TPML_PCR_SELECTION_Marshal (&pol_buf, &pcr_sel);
  623. grub_tpm2_buffer_init (&pub_buf);
  624. grub_Tss2_MU_TPM2B_PUBLIC_Marshal (&pub_buf, &sealed_key->public);
  625. grub_tpm2_buffer_init (&priv_buf);
  626. grub_Tss2_MU_TPM2B_Marshal (&priv_buf, sealed_key->private.size,
  627. sealed_key->private.buffer);
  628. if (pub_buf.error != 0 || priv_buf.error != 0)
  629. return GRUB_ERR_BAD_ARGUMENT;
  630. ret = asn1_array2tree (tpm2key_asn1_tab, &asn1_def, NULL);
  631. if (ret != ASN1_SUCCESS)
  632. return GRUB_ERR_BAD_ARGUMENT;
  633. ret = asn1_create_element (asn1_def, "TPM2KEY.TPMKey" , &tpm2key);
  634. if (ret != ASN1_SUCCESS)
  635. return GRUB_ERR_BAD_ARGUMENT;
  636. /* Set 'type' to "sealed key" */
  637. ret = asn1_write_value (tpm2key, "type", sealed_key_oid, 1);
  638. if (ret != ASN1_SUCCESS)
  639. {
  640. fprintf (stderr, "Failed to set 'type': 0x%u\n", ret);
  641. err = GRUB_ERR_BAD_ARGUMENT;
  642. goto error;
  643. }
  644. /* Set 'emptyAuth' to TRUE */
  645. ret = asn1_write_value (tpm2key, "emptyAuth", "TRUE", 1);
  646. if (ret != ASN1_SUCCESS)
  647. {
  648. fprintf (stderr, "Failed to set 'emptyAuth': 0x%x\n", ret);
  649. err = GRUB_ERR_BAD_ARGUMENT;
  650. goto error;
  651. }
  652. /* Set 'policy' */
  653. ret = asn1_write_value (tpm2key, "policy", "NEW", 1);
  654. if (ret != ASN1_SUCCESS)
  655. {
  656. fprintf (stderr, "Failed to set 'policy': 0x%x\n", ret);
  657. err = GRUB_ERR_BAD_ARGUMENT;
  658. goto error;
  659. }
  660. cmd_code = grub_cpu_to_be32 (TPM_CC_PolicyPCR);
  661. ret = asn1_write_value (tpm2key, "policy.?LAST.CommandCode", &cmd_code,
  662. sizeof (cmd_code));
  663. if (ret != ASN1_SUCCESS)
  664. {
  665. fprintf (stderr, "Failed to set 'policy CommandCode': 0x%x\n", ret);
  666. err = GRUB_ERR_BAD_ARGUMENT;
  667. goto error;
  668. }
  669. ret = asn1_write_value (tpm2key, "policy.?LAST.CommandPolicy", &pol_buf.data,
  670. pol_buf.size);
  671. if (ret != ASN1_SUCCESS)
  672. {
  673. fprintf (stderr, "Failed to set 'policy CommandPolicy': 0x%x\n", ret);
  674. err = GRUB_ERR_BAD_ARGUMENT;
  675. goto error;
  676. }
  677. /* Remove 'secret' */
  678. ret = asn1_write_value (tpm2key, "secret", NULL, 0);
  679. if (ret != ASN1_SUCCESS)
  680. {
  681. fprintf (stderr, "Failed to remove 'secret': 0x%x\n", ret);
  682. err = GRUB_ERR_BAD_ARGUMENT;
  683. goto error;
  684. }
  685. /* Remove 'authPolicy' */
  686. ret = asn1_write_value (tpm2key, "authPolicy", NULL, 0);
  687. if (ret != ASN1_SUCCESS)
  688. {
  689. fprintf (stderr, "Failed to remove 'authPolicy': 0x%x\n", ret);
  690. err = GRUB_ERR_BAD_ARGUMENT;
  691. goto error;
  692. }
  693. /* Remove 'description' */
  694. ret = asn1_write_value (tpm2key, "description", NULL, 0);
  695. if (ret != ASN1_SUCCESS)
  696. {
  697. fprintf (stderr, "Failed to remove 'description': 0x%x\n", ret);
  698. err = GRUB_ERR_BAD_ARGUMENT;
  699. goto error;
  700. }
  701. /*
  702. * Use the SRK handle as the parent handle if specified
  703. * Otherwise, Use TPM_RH_OWNER as the default parent handle
  704. */
  705. if (args->tpm2_srk != 0)
  706. parent = grub_cpu_to_be32 (args->tpm2_srk);
  707. else
  708. parent = grub_cpu_to_be32 (TPM_RH_OWNER);
  709. ret = asn1_write_value (tpm2key, "parent", &parent, sizeof (parent));
  710. if (ret != ASN1_SUCCESS)
  711. {
  712. fprintf (stderr, "Failed to set 'parent': 0x%x\n", ret);
  713. err = GRUB_ERR_BAD_ARGUMENT;
  714. goto error;
  715. }
  716. /*
  717. * Set 'rsaParent' to TRUE if the RSA SRK is specified and the SRK
  718. * handle is not persistent. Otherwise, remove 'rsaParent'.
  719. */
  720. if (args->tpm2_srk == 0 && args->srk_type.type == TPM_ALG_RSA)
  721. ret = asn1_write_value (tpm2key, "rsaParent", "TRUE", 1);
  722. else
  723. ret = asn1_write_value (tpm2key, "rsaParent", NULL, 0);
  724. if (ret != ASN1_SUCCESS)
  725. {
  726. fprintf (stderr, "Failed to set 'rsaParent': 0x%x\n", ret);
  727. err = GRUB_ERR_BAD_ARGUMENT;
  728. goto error;
  729. }
  730. /* Set the pubkey */
  731. ret = asn1_write_value (tpm2key, "pubkey", pub_buf.data, pub_buf.size);
  732. if (ret != ASN1_SUCCESS)
  733. {
  734. fprintf (stderr, "Failed to set 'pubkey': 0x%x\n", ret);
  735. err = GRUB_ERR_BAD_ARGUMENT;
  736. goto error;
  737. }
  738. /* Set the privkey */
  739. ret = asn1_write_value (tpm2key, "privkey", priv_buf.data, priv_buf.size);
  740. if (ret != ASN1_SUCCESS)
  741. {
  742. fprintf (stderr, "Failed to set 'privkey': 0x%x\n", ret);
  743. err = GRUB_ERR_BAD_ARGUMENT;
  744. goto error;
  745. }
  746. /* Create the DER binary */
  747. der_buf_size = 0;
  748. ret = asn1_der_coding (tpm2key, "", NULL, &der_buf_size, NULL);
  749. if (ret != ASN1_MEM_ERROR)
  750. {
  751. fprintf (stderr, "Failed to get DER size: 0x%x\n", ret);
  752. err = GRUB_ERR_BAD_ARGUMENT;
  753. goto error;
  754. }
  755. der_buf = grub_malloc (der_buf_size);
  756. if (der_buf == NULL)
  757. {
  758. fprintf (stderr, "Failed to allocate memory for DER encoding\n");
  759. err = GRUB_ERR_OUT_OF_MEMORY;
  760. goto error;
  761. }
  762. ret = asn1_der_coding (tpm2key, "", der_buf, &der_buf_size, NULL);
  763. if (ret != ASN1_SUCCESS)
  764. {
  765. fprintf (stderr, "DER coding error: 0x%x\n", ret);
  766. err = GRUB_ERR_BAD_ARGUMENT;
  767. goto error;
  768. }
  769. err = protect_write_file (args->tpm2_outfile, der_buf, der_buf_size);
  770. if (err != GRUB_ERR_NONE)
  771. fprintf (stderr, N_("Could not write tpm2key file (%s).\n"), strerror (errno));
  772. error:
  773. grub_free (der_buf);
  774. if (tpm2key)
  775. asn1_delete_structure (&tpm2key);
  776. return err;
  777. }
  778. static grub_err_t
  779. protect_tpm2_export_sealed_key (const char *filepath,
  780. tpm2_sealed_key_t *sealed_key)
  781. {
  782. grub_err_t err;
  783. struct grub_tpm2_buffer buf;
  784. grub_tpm2_buffer_init (&buf);
  785. grub_Tss2_MU_TPM2B_PUBLIC_Marshal (&buf, &sealed_key->public);
  786. grub_Tss2_MU_TPM2B_Marshal (&buf, sealed_key->private.size,
  787. sealed_key->private.buffer);
  788. if (buf.error != 0)
  789. return GRUB_ERR_BAD_ARGUMENT;
  790. err = protect_write_file (filepath, buf.data, buf.size);
  791. if (err != GRUB_ERR_NONE)
  792. fprintf (stderr, N_("Could not write sealed key file (%s).\n"), strerror (errno));
  793. return err;
  794. }
  795. static grub_err_t
  796. protect_tpm2_add (protect_args_t *args)
  797. {
  798. grub_err_t err;
  799. grub_uint8_t *key = NULL;
  800. grub_size_t key_size;
  801. TPM_HANDLE_t srk;
  802. TPM2B_DIGEST_t policy_digest;
  803. tpm2_sealed_key_t sealed_key;
  804. err = protect_tpm2_open_device (args->tpm2_device);
  805. if (err != GRUB_ERR_NONE)
  806. return err;
  807. err = protect_read_file (args->tpm2_keyfile, (void **)&key, &key_size);
  808. if (err != GRUB_ERR_NONE)
  809. goto exit1;
  810. if (key_size > TPM_MAX_SYM_DATA)
  811. {
  812. fprintf (stderr, N_("Input key size larger than %u bytes.\n"), TPM_MAX_SYM_DATA);
  813. err = GRUB_ERR_OUT_OF_RANGE;
  814. goto exit2;
  815. }
  816. err = protect_tpm2_get_srk (args, &srk);
  817. if (err != GRUB_ERR_NONE)
  818. goto exit2;
  819. err = protect_tpm2_get_policy_digest (args, &policy_digest);
  820. if (err != GRUB_ERR_NONE)
  821. goto exit3;
  822. err = protect_tpm2_seal (&policy_digest, srk, key, key_size, &sealed_key);
  823. if (err != GRUB_ERR_NONE)
  824. goto exit3;
  825. if (args->tpm2_tpm2key != 0)
  826. err = protect_tpm2_export_tpm2key (args, &sealed_key);
  827. else
  828. err = protect_tpm2_export_sealed_key (args->tpm2_outfile, &sealed_key);
  829. if (err != GRUB_ERR_NONE)
  830. goto exit3;
  831. exit3:
  832. grub_tpm2_flushcontext (srk);
  833. exit2:
  834. grub_free (key);
  835. exit1:
  836. protect_tpm2_close_device ();
  837. return err;
  838. }
  839. static grub_err_t
  840. protect_tpm2_remove (protect_args_t *args)
  841. {
  842. TPM_RC_t rc;
  843. TPM2B_PUBLIC_t public;
  844. TPMS_AUTH_COMMAND_t authCommand = {0};
  845. grub_err_t err;
  846. if (args->tpm2_evict == 0)
  847. {
  848. printf ("--tpm2-evict not specified, nothing to do.\n");
  849. return GRUB_ERR_NONE;
  850. }
  851. err = protect_tpm2_open_device (args->tpm2_device);
  852. if (err != GRUB_ERR_NONE)
  853. return err;
  854. /* Find SRK */
  855. rc = grub_tpm2_readpublic (args->tpm2_srk, NULL, &public);
  856. if (rc != TPM_RC_SUCCESS)
  857. {
  858. fprintf (stderr, "SRK with handle 0x%x not found.\n", args->tpm2_srk);
  859. err = GRUB_ERR_BAD_ARGUMENT;
  860. goto exit1;
  861. }
  862. /* Evict SRK */
  863. authCommand.sessionHandle = TPM_RS_PW;
  864. rc = grub_tpm2_evictcontrol (TPM_RH_OWNER, args->tpm2_srk, &authCommand, args->tpm2_srk, NULL);
  865. if (rc != TPM_RC_SUCCESS)
  866. {
  867. fprintf (stderr, "Failed to evict SRK with handle 0x%x (TPM2_EvictControl: 0x%x).\n", args->tpm2_srk, rc);
  868. err = GRUB_ERR_BAD_DEVICE;
  869. goto exit2;
  870. }
  871. err = GRUB_ERR_NONE;
  872. exit2:
  873. grub_tpm2_flushcontext (args->tpm2_srk);
  874. exit1:
  875. protect_tpm2_close_device ();
  876. return GRUB_ERR_NONE;
  877. }
  878. static grub_err_t
  879. protect_tpm2_run (protect_args_t *args)
  880. {
  881. switch (args->action)
  882. {
  883. case PROTECT_ACTION_ADD:
  884. return protect_tpm2_add (args);
  885. case PROTECT_ACTION_REMOVE:
  886. return protect_tpm2_remove (args);
  887. default:
  888. return GRUB_ERR_BAD_ARGUMENT;
  889. }
  890. }
  891. static grub_err_t
  892. protect_tpm2_args_verify (protect_args_t *args)
  893. {
  894. if (args->tpm2_device == NULL)
  895. args->tpm2_device = "/dev/tpm0";
  896. switch (args->action)
  897. {
  898. case PROTECT_ACTION_ADD:
  899. if (args->args & PROTECT_ARG_TPM2_EVICT)
  900. {
  901. fprintf (stderr, N_("--tpm2-evict is invalid when --action is 'add'.\n"));
  902. return GRUB_ERR_BAD_ARGUMENT;
  903. }
  904. if (args->tpm2_keyfile == NULL)
  905. {
  906. fprintf (stderr, N_("--tpm2-keyfile must be specified.\n"));
  907. return GRUB_ERR_BAD_ARGUMENT;
  908. }
  909. if (args->tpm2_outfile == NULL)
  910. {
  911. fprintf (stderr, N_("--tpm2-outfile must be specified.\n"));
  912. return GRUB_ERR_BAD_ARGUMENT;
  913. }
  914. if (args->tpm2_pcr_count == 0)
  915. {
  916. args->tpm2_pcrs[0] = 7;
  917. args->tpm2_pcr_count = 1;
  918. }
  919. if (args->srk_type.type == TPM_ALG_ERROR)
  920. {
  921. args->srk_type.type = TPM_ALG_ECC;
  922. args->srk_type.detail.ecc_curve = TPM_ECC_NIST_P256;
  923. }
  924. if (args->tpm2_bank == TPM_ALG_ERROR)
  925. args->tpm2_bank = TPM_ALG_SHA256;
  926. break;
  927. case PROTECT_ACTION_REMOVE:
  928. if (args->args & PROTECT_ARG_TPM2_ASYMMETRIC)
  929. {
  930. fprintf (stderr, N_("--tpm2-asymmetric is invalid when --action is 'remove'.\n"));
  931. return GRUB_ERR_BAD_ARGUMENT;
  932. }
  933. if (args->args & PROTECT_ARG_TPM2_BANK)
  934. {
  935. fprintf (stderr, N_("--tpm2-bank is invalid when --action is 'remove'.\n"));
  936. return GRUB_ERR_BAD_ARGUMENT;
  937. }
  938. if (args->args & PROTECT_ARG_TPM2_KEYFILE)
  939. {
  940. fprintf (stderr, N_("--tpm2-keyfile is invalid when --action is 'remove'.\n"));
  941. return GRUB_ERR_BAD_ARGUMENT;
  942. }
  943. if (args->args & PROTECT_ARG_TPM2_OUTFILE)
  944. {
  945. fprintf (stderr, N_("--tpm2-outfile is invalid when --action is 'remove'.\n"));
  946. return GRUB_ERR_BAD_ARGUMENT;
  947. }
  948. if (args->args & PROTECT_ARG_TPM2_PCRS)
  949. {
  950. fprintf (stderr, N_("--tpm2-pcrs is invalid when --action is 'remove'.\n"));
  951. return GRUB_ERR_BAD_ARGUMENT;
  952. }
  953. if (args->tpm2_srk == 0)
  954. {
  955. fprintf (stderr, N_("--tpm2-srk is not specified when --action is 'remove'.\n"));
  956. return GRUB_ERR_BAD_ARGUMENT;
  957. }
  958. break;
  959. default:
  960. fprintf (stderr, N_("The TPM2 key protector only supports the following actions: add, remove.\n"));
  961. return GRUB_ERR_BAD_ARGUMENT;
  962. }
  963. return GRUB_ERR_NONE;
  964. }
  965. static error_t
  966. protect_argp_parser (int key, char *arg, struct argp_state *state)
  967. {
  968. grub_err_t err;
  969. protect_args_t *args = state->input;
  970. switch (key)
  971. {
  972. case PROTECT_OPT_ACTION:
  973. if (args->args & PROTECT_ARG_ACTION)
  974. {
  975. fprintf (stderr, N_("--action|-a can only be specified once.\n"));
  976. return EINVAL;
  977. }
  978. if (grub_strcmp (arg, "add") == 0)
  979. args->action = PROTECT_ACTION_ADD;
  980. else if (grub_strcmp (arg, "remove") == 0)
  981. args->action = PROTECT_ACTION_REMOVE;
  982. else
  983. {
  984. fprintf (stderr, N_("'%s' is not a valid action.\n"), arg);
  985. return EINVAL;
  986. }
  987. args->args |= PROTECT_ARG_ACTION;
  988. break;
  989. case PROTECT_OPT_PROTECTOR:
  990. if (args->args & PROTECT_ARG_PROTECTOR)
  991. {
  992. fprintf (stderr, N_("--protector|-p can only be specified once.\n"));
  993. return EINVAL;
  994. }
  995. if (grub_strcmp (arg, "tpm2") == 0)
  996. args->protector = PROTECT_TYPE_TPM2;
  997. else
  998. {
  999. fprintf (stderr, N_("'%s' is not a valid protector.\n"), arg);
  1000. return EINVAL;
  1001. }
  1002. args->args |= PROTECT_ARG_PROTECTOR;
  1003. break;
  1004. case PROTECT_OPT_TPM2_DEVICE:
  1005. if (args->args & PROTECT_ARG_TPM2_DEVICE)
  1006. {
  1007. fprintf (stderr, N_("--tpm2-device can only be specified once.\n"));
  1008. return EINVAL;
  1009. }
  1010. args->tpm2_device = xstrdup (arg);
  1011. args->args |= PROTECT_ARG_TPM2_DEVICE;
  1012. break;
  1013. case PROTECT_OPT_TPM2_PCRS:
  1014. if (args->args & PROTECT_ARG_TPM2_PCRS)
  1015. {
  1016. fprintf (stderr, N_("--tpm2-pcrs can only be specified once.\n"));
  1017. return EINVAL;
  1018. }
  1019. err = grub_tpm2_protector_parse_pcrs (arg, args->tpm2_pcrs,
  1020. &args->tpm2_pcr_count);
  1021. if (err != GRUB_ERR_NONE)
  1022. {
  1023. if (grub_errno != GRUB_ERR_NONE)
  1024. grub_print_error ();
  1025. return EINVAL;
  1026. }
  1027. args->args |= PROTECT_ARG_TPM2_PCRS;
  1028. break;
  1029. case PROTECT_OPT_TPM2_SRK:
  1030. if (args->args & PROTECT_ARG_TPM2_SRK)
  1031. {
  1032. fprintf (stderr, N_("--tpm2-srk can only be specified once.\n"));
  1033. return EINVAL;
  1034. }
  1035. err = grub_tpm2_protector_parse_tpm_handle (arg, &args->tpm2_srk);
  1036. if (err != GRUB_ERR_NONE)
  1037. {
  1038. if (grub_errno != GRUB_ERR_NONE)
  1039. grub_print_error ();
  1040. return EINVAL;
  1041. }
  1042. args->args |= PROTECT_ARG_TPM2_SRK;
  1043. break;
  1044. case PROTECT_OPT_TPM2_ASYMMETRIC:
  1045. if (args->args & PROTECT_ARG_TPM2_ASYMMETRIC)
  1046. {
  1047. fprintf (stderr, N_("--tpm2-asymmetric can only be specified once.\n"));
  1048. return EINVAL;
  1049. }
  1050. err = grub_tpm2_protector_parse_asymmetric (arg, &args->srk_type);
  1051. if (err != GRUB_ERR_NONE)
  1052. {
  1053. if (grub_errno != GRUB_ERR_NONE)
  1054. grub_print_error ();
  1055. return EINVAL;
  1056. }
  1057. args->args |= PROTECT_ARG_TPM2_ASYMMETRIC;
  1058. break;
  1059. case PROTECT_OPT_TPM2_BANK:
  1060. if (args->args & PROTECT_ARG_TPM2_BANK)
  1061. {
  1062. fprintf (stderr, N_("--tpm2-bank can only be specified once.\n"));
  1063. return EINVAL;
  1064. }
  1065. err = grub_tpm2_protector_parse_bank (arg, &args->tpm2_bank);
  1066. if (err != GRUB_ERR_NONE)
  1067. {
  1068. if (grub_errno != GRUB_ERR_NONE)
  1069. grub_print_error ();
  1070. return EINVAL;
  1071. }
  1072. args->args |= PROTECT_ARG_TPM2_BANK;
  1073. break;
  1074. case PROTECT_OPT_TPM2_KEYFILE:
  1075. if (args->args & PROTECT_ARG_TPM2_KEYFILE)
  1076. {
  1077. fprintf (stderr, N_("--tpm2-keyfile can only be specified once.\n"));
  1078. return EINVAL;
  1079. }
  1080. args->tpm2_keyfile = xstrdup(arg);
  1081. args->args |= PROTECT_ARG_TPM2_KEYFILE;
  1082. break;
  1083. case PROTECT_OPT_TPM2_OUTFILE:
  1084. if (args->args & PROTECT_ARG_TPM2_OUTFILE)
  1085. {
  1086. fprintf (stderr, N_("--tpm2-outfile can only be specified once.\n"));
  1087. return EINVAL;
  1088. }
  1089. args->tpm2_outfile = xstrdup(arg);
  1090. args->args |= PROTECT_ARG_TPM2_OUTFILE;
  1091. break;
  1092. case PROTECT_OPT_TPM2_EVICT:
  1093. if (args->args & PROTECT_ARG_TPM2_EVICT)
  1094. {
  1095. fprintf (stderr, N_("--tpm2-evict can only be specified once.\n"));
  1096. return EINVAL;
  1097. }
  1098. args->tpm2_evict = 1;
  1099. args->args |= PROTECT_ARG_TPM2_EVICT;
  1100. break;
  1101. case PROTECT_OPT_TPM2_TPM2KEY:
  1102. if (args->args & PROTECT_ARG_TPM2_TPM2KEY)
  1103. {
  1104. fprintf (stderr, N_("--tpm2-tpm2key can only be specified once.\n"));
  1105. return EINVAL;
  1106. }
  1107. args->tpm2_tpm2key = 1;
  1108. args->args |= PROTECT_ARG_TPM2_TPM2KEY;
  1109. break;
  1110. default:
  1111. return ARGP_ERR_UNKNOWN;
  1112. }
  1113. return 0;
  1114. }
  1115. static grub_err_t
  1116. protect_args_verify (protect_args_t *args)
  1117. {
  1118. if (args->action == PROTECT_ACTION_ERROR)
  1119. {
  1120. fprintf (stderr, N_("--action is mandatory.\n"));
  1121. return GRUB_ERR_BAD_ARGUMENT;
  1122. }
  1123. /*
  1124. * At the moment, the only configurable key protector is the TPM2 one, so it
  1125. * is the only key protector supported by this tool.
  1126. */
  1127. if (args->protector != PROTECT_TYPE_TPM2)
  1128. {
  1129. fprintf (stderr, N_("--protector is mandatory and only 'tpm2' is currently supported.\n"));
  1130. return GRUB_ERR_BAD_ARGUMENT;
  1131. }
  1132. switch (args->protector)
  1133. {
  1134. case PROTECT_TYPE_TPM2:
  1135. return protect_tpm2_args_verify (args);
  1136. default:
  1137. return GRUB_ERR_BAD_ARGUMENT;
  1138. }
  1139. return GRUB_ERR_NONE;
  1140. }
  1141. static grub_err_t
  1142. protect_dispatch (protect_args_t *args)
  1143. {
  1144. switch (args->protector)
  1145. {
  1146. case PROTECT_TYPE_TPM2:
  1147. return protect_tpm2_run (args);
  1148. default:
  1149. return GRUB_ERR_BAD_ARGUMENT;
  1150. }
  1151. }
  1152. static void
  1153. protect_init (int *argc, char **argv[])
  1154. {
  1155. grub_util_host_init (argc, argv);
  1156. grub_util_biosdisk_init (NULL);
  1157. grub_init_all ();
  1158. grub_lvm_fini ();
  1159. grub_mdraid09_fini ();
  1160. grub_mdraid1x_fini ();
  1161. grub_diskfilter_fini ();
  1162. grub_diskfilter_init ();
  1163. grub_mdraid09_init ();
  1164. grub_mdraid1x_init ();
  1165. grub_lvm_init ();
  1166. }
  1167. static void
  1168. protect_fini (void)
  1169. {
  1170. grub_fini_all ();
  1171. grub_util_biosdisk_fini ();
  1172. }
  1173. static struct argp protect_argp =
  1174. {
  1175. .options = protect_options,
  1176. .parser = protect_argp_parser,
  1177. .args_doc = NULL,
  1178. .doc =
  1179. N_("Protect a cleartext key using a GRUB key protector that can retrieve "
  1180. "the key during boot to unlock fully-encrypted disks automatically."),
  1181. .children = NULL,
  1182. .help_filter = NULL,
  1183. .argp_domain = NULL
  1184. };
  1185. int
  1186. main (int argc, char *argv[])
  1187. {
  1188. grub_err_t err;
  1189. protect_args_t args = {0};
  1190. if (argp_parse (&protect_argp, argc, argv, 0, 0, &args) != 0)
  1191. {
  1192. fprintf (stderr, N_("Could not parse arguments.\n"));
  1193. return EXIT_FAILURE;
  1194. }
  1195. protect_init (&argc, &argv);
  1196. err = protect_args_verify (&args);
  1197. if (err != GRUB_ERR_NONE)
  1198. goto exit;
  1199. err = protect_dispatch (&args);
  1200. exit:
  1201. protect_fini ();
  1202. if (err != GRUB_ERR_NONE)
  1203. return EXIT_FAILURE;
  1204. return EXIT_SUCCESS;
  1205. }