From 14793c1f966af25ccb9bafda4db887de7b1f7218f8b9d14f4092088ad05f2944 Mon Sep 17 00:00:00 2001 From: Michael Chang Date: Thu, 11 Aug 2022 10:30:46 +0000 Subject: [PATCH] Accepting request 992180 from home:michael-chang:branches:home:michael-chang:test:tpm - Add tpm, tpm2, luks2 and gcry_sha512 to default grub.efi (bsc#1197625) - Make grub-tpm.efi a symlink to grub.efi * grub2.spec - Log error when tpm event log is full and continue * 0001-tpm-Log-EFI_VOLUME_FULL-and-continue.patch - Patch superseded * 0001-tpm-Pass-unknown-error-as-non-fatal-but-debug-print-.patch - Add patches for automatic TPM disk unlock (jsc#SLE-24018) (bsc#1196668) * 0001-luks2-Add-debug-message-to-align-with-luks-and-geli-.patch * 0002-cryptodisk-Refactor-to-discard-have_it-global.patch * 0003-cryptodisk-Return-failure-in-cryptomount-when-no-cry.patch * 0004-cryptodisk-Improve-error-messaging-in-cryptomount-in.patch * 0005-cryptodisk-Improve-cryptomount-u-error-message.patch * 0006-cryptodisk-Add-infrastructure-to-pass-data-from-cryp.patch * 0007-cryptodisk-Refactor-password-input-out-of-crypto-dev.patch * 0008-cryptodisk-Move-global-variables-into-grub_cryptomou.patch * 0009-cryptodisk-Improve-handling-of-partition-name-in-cry.patch * 0010-protectors-Add-key-protectors-framework.patch * 0011-tpm2-Add-TPM-Software-Stack-TSS.patch * 0012-protectors-Add-TPM2-Key-Protector.patch * 0013-cryptodisk-Support-key-protectors.patch * 0014-util-grub-protect-Add-new-tool.patch - Fix no disk unlocking happen (bsc#1196668) * 0001-crytodisk-fix-cryptodisk-module-looking-up.patch - Fix build error * fix-tpm2-build.patch OBS-URL: https://build.opensuse.org/request/show/992180 OBS-URL: https://build.opensuse.org/package/show/Base:System/grub2?expand=0&rev=417 --- ...isk-fix-cryptodisk-module-looking-up.patch | 33 + ...message-to-align-with-luks-and-geli-.patch | 31 + ...tpm-Log-EFI_VOLUME_FULL-and-continue.patch | 82 + ...-error-as-non-fatal-but-debug-print-.patch | 29 - ...k-Refactor-to-discard-have_it-global.patch | 187 + ...n-failure-in-cryptomount-when-no-cry.patch | 32 + ...ve-error-messaging-in-cryptomount-in.patch | 58 + ...-Improve-cryptomount-u-error-message.patch | 31 + ...nfrastructure-to-pass-data-from-cryp.patch | 252 ++ ...tor-password-input-out-of-crypto-dev.patch | 342 ++ ...global-variables-into-grub_cryptomou.patch | 248 ++ ...ve-handling-of-partition-name-in-cry.patch | 39 + ...tectors-Add-key-protectors-framework.patch | 189 + 0011-tpm2-Add-TPM-Software-Stack-TSS.patch | 3523 +++++++++++++++++ 0012-protectors-Add-TPM2-Key-Protector.patch | 977 +++++ 0013-cryptodisk-Support-key-protectors.patch | 336 ++ 0014-util-grub-protect-Add-new-tool.patch | 1408 +++++++ fix-tpm2-build.patch | 38 + grub2.changes | 34 + grub2.spec | 32 +- 20 files changed, 7861 insertions(+), 40 deletions(-) create mode 100644 0001-crytodisk-fix-cryptodisk-module-looking-up.patch create mode 100644 0001-luks2-Add-debug-message-to-align-with-luks-and-geli-.patch create mode 100644 0001-tpm-Log-EFI_VOLUME_FULL-and-continue.patch delete mode 100644 0001-tpm-Pass-unknown-error-as-non-fatal-but-debug-print-.patch create mode 100644 0002-cryptodisk-Refactor-to-discard-have_it-global.patch create mode 100644 0003-cryptodisk-Return-failure-in-cryptomount-when-no-cry.patch create mode 100644 0004-cryptodisk-Improve-error-messaging-in-cryptomount-in.patch create mode 100644 0005-cryptodisk-Improve-cryptomount-u-error-message.patch create mode 100644 0006-cryptodisk-Add-infrastructure-to-pass-data-from-cryp.patch create mode 100644 0007-cryptodisk-Refactor-password-input-out-of-crypto-dev.patch create mode 100644 0008-cryptodisk-Move-global-variables-into-grub_cryptomou.patch create mode 100644 0009-cryptodisk-Improve-handling-of-partition-name-in-cry.patch create mode 100644 0010-protectors-Add-key-protectors-framework.patch create mode 100644 0011-tpm2-Add-TPM-Software-Stack-TSS.patch create mode 100644 0012-protectors-Add-TPM2-Key-Protector.patch create mode 100644 0013-cryptodisk-Support-key-protectors.patch create mode 100644 0014-util-grub-protect-Add-new-tool.patch create mode 100644 fix-tpm2-build.patch diff --git a/0001-crytodisk-fix-cryptodisk-module-looking-up.patch b/0001-crytodisk-fix-cryptodisk-module-looking-up.patch new file mode 100644 index 0000000..f19c0d0 --- /dev/null +++ b/0001-crytodisk-fix-cryptodisk-module-looking-up.patch @@ -0,0 +1,33 @@ +From 822f71318a69c150da3ad7df5fe8667dfa6e8069 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Thu, 31 Mar 2022 15:45:35 +0800 +Subject: [PATCH] crytodisk: fix cryptodisk module looking up + +The error "no cryptodisk module can handle this device" may happen even +encrypted disk were correctly formatted and required modules were loaded. + +It is casued by missing break to the loop in which cryptodisk modules are +iterated to find the one matching target's disk format. With the break +statement, the loop will be always ended with testing last cryptodisk module on +the list that may not be able to handle the format of encrypted disk's. + +Signed-off-by: Michael Chang +--- + grub-core/disk/cryptodisk.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c +index 00c44773fb..6d22bf871c 100644 +--- a/grub-core/disk/cryptodisk.c ++++ b/grub-core/disk/cryptodisk.c +@@ -1021,6 +1021,7 @@ grub_cryptodisk_scan_device_real (const char *name, + if (!dev) + continue; + crd = cr; ++ break; + } + + if (!dev) +-- +2.34.1 + diff --git a/0001-luks2-Add-debug-message-to-align-with-luks-and-geli-.patch b/0001-luks2-Add-debug-message-to-align-with-luks-and-geli-.patch new file mode 100644 index 0000000..20d869e --- /dev/null +++ b/0001-luks2-Add-debug-message-to-align-with-luks-and-geli-.patch @@ -0,0 +1,31 @@ +From 8eae4c33a32d9951641e289d2809a92a223b1642 Mon Sep 17 00:00:00 2001 +From: Glenn Washburn +Date: Thu, 9 Dec 2021 11:14:50 -0600 +Subject: [PATCH 01/14] luks2: Add debug message to align with luks and geli + modules + +Signed-off-by: Glenn Washburn +Reviewed-by: Daniel Kiper +--- + grub-core/disk/luks2.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/grub-core/disk/luks2.c b/grub-core/disk/luks2.c +index 371a53b837..fea196dd4a 100644 +--- a/grub-core/disk/luks2.c ++++ b/grub-core/disk/luks2.c +@@ -370,7 +370,10 @@ luks2_scan (grub_disk_t disk, const char *check_uuid, int check_boot) + uuid[j] = '\0'; + + if (check_uuid && grub_strcasecmp (check_uuid, uuid) != 0) +- return NULL; ++ { ++ grub_dprintf ("luks2", "%s != %s\n", uuid, check_uuid); ++ return NULL; ++ } + + cryptodisk = grub_zalloc (sizeof (*cryptodisk)); + if (!cryptodisk) +-- +2.34.1 + diff --git a/0001-tpm-Log-EFI_VOLUME_FULL-and-continue.patch b/0001-tpm-Log-EFI_VOLUME_FULL-and-continue.patch new file mode 100644 index 0000000..7ac030c --- /dev/null +++ b/0001-tpm-Log-EFI_VOLUME_FULL-and-continue.patch @@ -0,0 +1,82 @@ +From 8c9f7cefdf9d03cae65773ef35e103fc346ee17f Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Tue, 3 May 2022 12:38:34 +0800 +Subject: [PATCH] tpm: Log EFI_VOLUME_FULL and continue + +Appending entries to tpm event log would fail if it is full and in this +case EFI_VOLUME_FULL is returned. Since the measurement itself is +successful but only the event is not logged, the booting shouldn't be +forced to stop and instead grub should log the error and continue. + +All errors other than EFI_VOLUME_FULL remains to stop grub from booting +so the failure can be examined. In case of unknown tpm error, the return +code from efi firmware is also displayed for reference. + +Signed-off-by: Michael Chang +--- + grub-core/commands/efi/tpm.c | 20 +++++++++++++++++--- + 1 file changed, 17 insertions(+), 3 deletions(-) + +diff --git a/grub-core/commands/efi/tpm.c b/grub-core/commands/efi/tpm.c +index a97d85368a..98fd5892b0 100644 +--- a/grub-core/commands/efi/tpm.c ++++ b/grub-core/commands/efi/tpm.c +@@ -144,8 +144,10 @@ grub_efi_log_event_status (grub_efi_status_t status) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Output buffer too small")); + case GRUB_EFI_NOT_FOUND: + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("TPM unavailable")); ++ case GRUB_EFI_VOLUME_FULL: ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("TPM event log is full")); + default: +- return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("Unknown TPM error")); ++ return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("Unknown TPM error: %" PRIuGRUB_SIZE), status); + } + } + +@@ -159,6 +161,7 @@ grub_tpm1_log_event (grub_efi_handle_t tpm_handle, unsigned char *buf, + grub_efi_tpm_protocol_t *tpm; + grub_efi_physical_address_t lastevent; + grub_uint32_t algorithm; ++ grub_err_t err; + grub_uint32_t eventnum = 0; + + tpm = grub_efi_open_protocol (tpm_handle, &tpm_guid, +@@ -182,7 +185,12 @@ grub_tpm1_log_event (grub_efi_handle_t tpm_handle, unsigned char *buf, + algorithm, event, &eventnum, &lastevent); + grub_free (event); + +- return grub_efi_log_event_status (status); ++ err = grub_efi_log_event_status (status); ++ /* Log EFI_VOLUME_FULL and continue */ ++ if (err == GRUB_ERR_OUT_OF_RANGE) ++ grub_print_error (); ++ ++ return err; + } + + static grub_err_t +@@ -193,6 +201,7 @@ grub_tpm2_log_event (grub_efi_handle_t tpm_handle, unsigned char *buf, + EFI_TCG2_EVENT *event; + grub_efi_status_t status; + grub_efi_tpm2_protocol_t *tpm; ++ grub_err_t err; + + tpm = grub_efi_open_protocol (tpm_handle, &tpm2_guid, + GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); +@@ -218,7 +227,12 @@ grub_tpm2_log_event (grub_efi_handle_t tpm_handle, unsigned char *buf, + (grub_uint64_t) size, event); + grub_free (event); + +- return grub_efi_log_event_status (status); ++ err = grub_efi_log_event_status (status); ++ /* Log EFI_VOLUME_FULL and continue */ ++ if (err == GRUB_ERR_OUT_OF_RANGE) ++ grub_print_error (); ++ ++ return err; + } + + grub_err_t +-- +2.34.1 + diff --git a/0001-tpm-Pass-unknown-error-as-non-fatal-but-debug-print-.patch b/0001-tpm-Pass-unknown-error-as-non-fatal-but-debug-print-.patch deleted file mode 100644 index b37dfb4..0000000 --- a/0001-tpm-Pass-unknown-error-as-non-fatal-but-debug-print-.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 2cecb472ffba4dbc534f4ce3346a453762371c52 Mon Sep 17 00:00:00 2001 -From: Mathieu Trudel-Lapierre -Date: Fri, 25 Oct 2019 10:27:54 -0400 -Subject: [PATCH] tpm: Pass unknown error as non-fatal, but debug print the - error we got - -Signed-off-by: Mathieu Trudel-Lapierre -Patch-Name: ubuntu-tpm-unknown-error-non-fatal.patch ---- - grub-core/commands/efi/tpm.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/grub-core/commands/efi/tpm.c b/grub-core/commands/efi/tpm.c -index a97d85368..1e399a964 100644 ---- a/grub-core/commands/efi/tpm.c -+++ b/grub-core/commands/efi/tpm.c -@@ -145,7 +145,8 @@ grub_efi_log_event_status (grub_efi_status_t status) - case GRUB_EFI_NOT_FOUND: - return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("TPM unavailable")); - default: -- return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("Unknown TPM error")); -+ grub_dprintf("tpm", "Unknown TPM error: %" PRIdGRUB_SSIZE, status); -+ return 0; - } - } - --- -2.31.1 - diff --git a/0002-cryptodisk-Refactor-to-discard-have_it-global.patch b/0002-cryptodisk-Refactor-to-discard-have_it-global.patch new file mode 100644 index 0000000..a7a0555 --- /dev/null +++ b/0002-cryptodisk-Refactor-to-discard-have_it-global.patch @@ -0,0 +1,187 @@ +From 4ace73cc192bc63a00f4208b34981a6d91947811 Mon Sep 17 00:00:00 2001 +From: Glenn Washburn +Date: Thu, 9 Dec 2021 11:14:51 -0600 +Subject: [PATCH 02/14] cryptodisk: Refactor to discard have_it global + +The global "have_it" was never used by the crypto-backends, but was used to +determine if a crypto-backend successfully mounted a cryptodisk with a given +UUID. This is not needed however, because grub_device_iterate() will return +1 if and only if grub_cryptodisk_scan_device() returns 1. And +grub_cryptodisk_scan_device() will now only return 1 if a search_uuid has +been specified and a cryptodisk was successfully setup by a crypto-backend or +a cryptodisk of the requested UUID is already open. + +To implement this grub_cryptodisk_scan_device_real() is modified to return +a cryptodisk or NULL on failure and having the appropriate grub_errno set to +indicated failure. Note that grub_cryptodisk_scan_device_real() will fail now +with a new errno GRUB_ERR_BAD_MODULE when none of the cryptodisk backend +modules succeed in identifying the source disk. + +With this change grub_device_iterate() will return 1 when a crypto device is +successfully decrypted or when the source device has already been successfully +opened. Prior to this change, trying to mount an already successfully opened +device would trigger an error with the message "no such cryptodisk found", +which is at best misleading. The mount should silently succeed in this case, +which is what happens with this patch. + +Signed-off-by: Glenn Washburn +Reviewed-by: Daniel Kiper +--- + grub-core/disk/cryptodisk.c | 56 +++++++++++++++++++++++-------------- + 1 file changed, 35 insertions(+), 21 deletions(-) + +diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c +index 90f82b2d39..9df3d310fe 100644 +--- a/grub-core/disk/cryptodisk.c ++++ b/grub-core/disk/cryptodisk.c +@@ -983,7 +983,7 @@ grub_util_cryptodisk_get_uuid (grub_disk_t disk) + + #endif + +-static int check_boot, have_it; ++static int check_boot; + static char *search_uuid; + + static void +@@ -995,7 +995,7 @@ cryptodisk_close (grub_cryptodisk_t dev) + grub_free (dev); + } + +-static grub_err_t ++static grub_cryptodisk_t + grub_cryptodisk_scan_device_real (const char *name, grub_disk_t source) + { + grub_err_t err; +@@ -1005,13 +1005,13 @@ grub_cryptodisk_scan_device_real (const char *name, grub_disk_t source) + dev = grub_cryptodisk_get_by_source_disk (source); + + if (dev) +- return GRUB_ERR_NONE; ++ return dev; + + FOR_CRYPTODISK_DEVS (cr) + { + dev = cr->scan (source, search_uuid, check_boot); + if (grub_errno) +- return grub_errno; ++ return NULL; + if (!dev) + continue; + +@@ -1019,16 +1019,16 @@ grub_cryptodisk_scan_device_real (const char *name, grub_disk_t source) + if (err) + { + cryptodisk_close (dev); +- return err; ++ return NULL; + } + + grub_cryptodisk_insert (dev, name, source); + +- have_it = 1; +- +- return GRUB_ERR_NONE; ++ return dev; + } +- return GRUB_ERR_NONE; ++ ++ grub_error (GRUB_ERR_BAD_MODULE, "no cryptodisk module can handle this device"); ++ return NULL; + } + + #ifdef GRUB_UTIL +@@ -1082,8 +1082,10 @@ static int + grub_cryptodisk_scan_device (const char *name, + void *data __attribute__ ((unused))) + { +- grub_err_t err; ++ int ret = 0; + grub_disk_t source; ++ grub_cryptodisk_t dev; ++ grub_errno = GRUB_ERR_NONE; + + /* Try to open disk. */ + source = grub_disk_open (name); +@@ -1093,13 +1095,26 @@ grub_cryptodisk_scan_device (const char *name, + return 0; + } + +- err = grub_cryptodisk_scan_device_real (name, source); ++ dev = grub_cryptodisk_scan_device_real (name, source); ++ if (dev) ++ { ++ ret = (search_uuid != NULL && grub_strcasecmp (search_uuid, dev->uuid) == 0); ++ goto cleanup; ++ } + +- grub_disk_close (source); +- +- if (err) ++ /* ++ * Do not print error when err is GRUB_ERR_BAD_MODULE to avoid many unhelpful ++ * error messages. ++ */ ++ if (grub_errno == GRUB_ERR_BAD_MODULE) ++ grub_error_pop (); ++ ++ if (grub_errno != GRUB_ERR_NONE) + grub_print_error (); +- return have_it && search_uuid ? 1 : 0; ++ ++ cleanup: ++ grub_disk_close (source); ++ return ret; + } + + static grub_err_t +@@ -1110,9 +1125,9 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) + if (argc < 1 && !state[1].set && !state[2].set) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required"); + +- have_it = 0; + if (state[0].set) + { ++ int found_uuid; + grub_cryptodisk_t dev; + + dev = grub_cryptodisk_get_by_uuid (args[0]); +@@ -1125,10 +1140,10 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) + + check_boot = state[2].set; + search_uuid = args[0]; +- grub_device_iterate (&grub_cryptodisk_scan_device, NULL); ++ found_uuid = grub_device_iterate (&grub_cryptodisk_scan_device, NULL); + search_uuid = NULL; + +- if (!have_it) ++ if (!found_uuid) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "no such cryptodisk found"); + return GRUB_ERR_NONE; + } +@@ -1142,7 +1157,6 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) + } + else + { +- grub_err_t err; + grub_disk_t disk; + grub_cryptodisk_t dev; + char *diskname; +@@ -1178,13 +1192,13 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) + return GRUB_ERR_NONE; + } + +- err = grub_cryptodisk_scan_device_real (diskname, disk); ++ dev = grub_cryptodisk_scan_device_real (diskname, disk); + + grub_disk_close (disk); + if (disklast) + *disklast = ')'; + +- return err; ++ return (dev == NULL) ? grub_errno : GRUB_ERR_NONE; + } + } + +-- +2.34.1 + diff --git a/0003-cryptodisk-Return-failure-in-cryptomount-when-no-cry.patch b/0003-cryptodisk-Return-failure-in-cryptomount-when-no-cry.patch new file mode 100644 index 0000000..a720702 --- /dev/null +++ b/0003-cryptodisk-Return-failure-in-cryptomount-when-no-cry.patch @@ -0,0 +1,32 @@ +From 86fe3bbbf75e62387cc9842654fd6c852e9457a6 Mon Sep 17 00:00:00 2001 +From: Glenn Washburn +Date: Thu, 9 Dec 2021 11:14:52 -0600 +Subject: [PATCH 03/14] cryptodisk: Return failure in cryptomount when no + cryptodisk modules are loaded + +This displays an error notifying the user that they'll want to load +a backend module to make cryptomount useful. + +Signed-off-by: Glenn Washburn +Reviewed-by: Daniel Kiper +--- + grub-core/disk/cryptodisk.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c +index 9df3d310fe..27491871a5 100644 +--- a/grub-core/disk/cryptodisk.c ++++ b/grub-core/disk/cryptodisk.c +@@ -1125,6 +1125,9 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) + if (argc < 1 && !state[1].set && !state[2].set) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required"); + ++ if (grub_cryptodisk_list == NULL) ++ return grub_error (GRUB_ERR_BAD_MODULE, "no cryptodisk modules loaded"); ++ + if (state[0].set) + { + int found_uuid; +-- +2.34.1 + diff --git a/0004-cryptodisk-Improve-error-messaging-in-cryptomount-in.patch b/0004-cryptodisk-Improve-error-messaging-in-cryptomount-in.patch new file mode 100644 index 0000000..775368a --- /dev/null +++ b/0004-cryptodisk-Improve-error-messaging-in-cryptomount-in.patch @@ -0,0 +1,58 @@ +From f41488d0e361a34f4d3f8fb6c92729a2901a5c76 Mon Sep 17 00:00:00 2001 +From: Glenn Washburn +Date: Thu, 9 Dec 2021 11:14:53 -0600 +Subject: [PATCH 04/14] cryptodisk: Improve error messaging in cryptomount + invocations + +Update such that "cryptomount -u UUID" will not print two error messages +when an invalid passphrase is given and the most relevant error message +will be displayed. + +Signed-off-by: Glenn Washburn +Reviewed-by: Daniel Kiper +--- + grub-core/disk/cryptodisk.c | 21 +++++++++++++++++---- + 1 file changed, 17 insertions(+), 4 deletions(-) + +diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c +index 27491871a5..3a896c6634 100644 +--- a/grub-core/disk/cryptodisk.c ++++ b/grub-core/disk/cryptodisk.c +@@ -1109,7 +1109,10 @@ grub_cryptodisk_scan_device (const char *name, + if (grub_errno == GRUB_ERR_BAD_MODULE) + grub_error_pop (); + +- if (grub_errno != GRUB_ERR_NONE) ++ if (search_uuid != NULL) ++ /* Push error onto stack to save for cryptomount. */ ++ grub_error_push (); ++ else + grub_print_error (); + + cleanup: +@@ -1146,9 +1149,19 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) + found_uuid = grub_device_iterate (&grub_cryptodisk_scan_device, NULL); + search_uuid = NULL; + +- if (!found_uuid) +- return grub_error (GRUB_ERR_BAD_ARGUMENT, "no such cryptodisk found"); +- return GRUB_ERR_NONE; ++ if (found_uuid) ++ return GRUB_ERR_NONE; ++ else if (grub_errno == GRUB_ERR_NONE) ++ { ++ /* ++ * Try to pop the next error on the stack. If there is not one, then ++ * no device matched the given UUID. ++ */ ++ grub_error_pop (); ++ if (grub_errno == GRUB_ERR_NONE) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "no such cryptodisk found"); ++ } ++ return grub_errno; + } + else if (state[1].set || (argc == 0 && state[2].set)) + { +-- +2.34.1 + diff --git a/0005-cryptodisk-Improve-cryptomount-u-error-message.patch b/0005-cryptodisk-Improve-cryptomount-u-error-message.patch new file mode 100644 index 0000000..64d03c6 --- /dev/null +++ b/0005-cryptodisk-Improve-cryptomount-u-error-message.patch @@ -0,0 +1,31 @@ +From 9ef619a7c1d38988f6d91496ea5c59062dcf6013 Mon Sep 17 00:00:00 2001 +From: Glenn Washburn +Date: Thu, 9 Dec 2021 11:14:54 -0600 +Subject: [PATCH 05/14] cryptodisk: Improve cryptomount -u error message + +When a cryptmount is specified with a UUID, but no cryptodisk backends find +a disk with that UUID, return a more detailed message giving telling the +user that they might not have a needed cryptobackend module loaded. + +Signed-off-by: Glenn Washburn +Reviewed-by: Daniel Kiper +--- + grub-core/disk/cryptodisk.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c +index 3a896c6634..5a9780b14c 100644 +--- a/grub-core/disk/cryptodisk.c ++++ b/grub-core/disk/cryptodisk.c +@@ -1159,7 +1159,7 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) + */ + grub_error_pop (); + if (grub_errno == GRUB_ERR_NONE) +- return grub_error (GRUB_ERR_BAD_ARGUMENT, "no such cryptodisk found"); ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "no such cryptodisk found, perhaps a needed disk or cryptodisk module is not loaded"); + } + return grub_errno; + } +-- +2.34.1 + diff --git a/0006-cryptodisk-Add-infrastructure-to-pass-data-from-cryp.patch b/0006-cryptodisk-Add-infrastructure-to-pass-data-from-cryp.patch new file mode 100644 index 0000000..91fb26d --- /dev/null +++ b/0006-cryptodisk-Add-infrastructure-to-pass-data-from-cryp.patch @@ -0,0 +1,252 @@ +From 0a5619abd170b3ad43e44cb8036062506d8623cc Mon Sep 17 00:00:00 2001 +From: Glenn Washburn +Date: Thu, 9 Dec 2021 11:14:55 -0600 +Subject: [PATCH 06/14] cryptodisk: Add infrastructure to pass data from + cryptomount to cryptodisk modules + +Previously, the cryptomount arguments were passed by global variable and +function call argument, neither of which are ideal. This change passes data +via a grub_cryptomount_args struct, which can be added to over time as +opposed to continually adding arguments to the cryptodisk scan and +recover_key. + +As an example, passing a password as a cryptomount argument is implemented. +However, the backends are not implemented, so testing this will return a not +implemented error. + +Also, add comments to cryptomount argument parsing to make it more obvious +which argument states are being handled. + +Signed-off-by: Glenn Washburn +Reviewed-by: Daniel Kiper +--- + grub-core/disk/cryptodisk.c | 31 +++++++++++++++++++++---------- + grub-core/disk/geli.c | 6 +++++- + grub-core/disk/luks.c | 7 ++++++- + grub-core/disk/luks2.c | 7 ++++++- + include/grub/cryptodisk.h | 9 ++++++++- + 5 files changed, 46 insertions(+), 14 deletions(-) + +diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c +index 5a9780b14c..14c661a86e 100644 +--- a/grub-core/disk/cryptodisk.c ++++ b/grub-core/disk/cryptodisk.c +@@ -41,6 +41,7 @@ static const struct grub_arg_option options[] = + /* TRANSLATORS: It's still restricted to cryptodisks only. */ + {"all", 'a', 0, N_("Mount all."), 0, 0}, + {"boot", 'b', 0, N_("Mount all volumes with `boot' flag set."), 0, 0}, ++ {"password", 'p', 0, N_("Password to open volumes."), 0, ARG_TYPE_STRING}, + {0, 0, 0, 0, 0, 0} + }; + +@@ -996,7 +997,9 @@ cryptodisk_close (grub_cryptodisk_t dev) + } + + static grub_cryptodisk_t +-grub_cryptodisk_scan_device_real (const char *name, grub_disk_t source) ++grub_cryptodisk_scan_device_real (const char *name, ++ grub_disk_t source, ++ grub_cryptomount_args_t cargs) + { + grub_err_t err; + grub_cryptodisk_t dev; +@@ -1015,7 +1018,7 @@ grub_cryptodisk_scan_device_real (const char *name, grub_disk_t source) + if (!dev) + continue; + +- err = cr->recover_key (source, dev); ++ err = cr->recover_key (source, dev, cargs); + if (err) + { + cryptodisk_close (dev); +@@ -1080,11 +1083,12 @@ grub_cryptodisk_cheat_mount (const char *sourcedev, const char *cheat) + + static int + grub_cryptodisk_scan_device (const char *name, +- void *data __attribute__ ((unused))) ++ void *data) + { + int ret = 0; + grub_disk_t source; + grub_cryptodisk_t dev; ++ grub_cryptomount_args_t cargs = data; + grub_errno = GRUB_ERR_NONE; + + /* Try to open disk. */ +@@ -1095,7 +1099,7 @@ grub_cryptodisk_scan_device (const char *name, + return 0; + } + +- dev = grub_cryptodisk_scan_device_real (name, source); ++ dev = grub_cryptodisk_scan_device_real (name, source, cargs); + if (dev) + { + ret = (search_uuid != NULL && grub_strcasecmp (search_uuid, dev->uuid) == 0); +@@ -1124,6 +1128,7 @@ static grub_err_t + grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) + { + struct grub_arg_list *state = ctxt->state; ++ struct grub_cryptomount_args cargs = {0}; + + if (argc < 1 && !state[1].set && !state[2].set) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required"); +@@ -1131,7 +1136,13 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) + if (grub_cryptodisk_list == NULL) + return grub_error (GRUB_ERR_BAD_MODULE, "no cryptodisk modules loaded"); + +- if (state[0].set) ++ if (state[3].set) /* password */ ++ { ++ cargs.key_data = (grub_uint8_t *) state[3].arg; ++ cargs.key_len = grub_strlen (state[3].arg); ++ } ++ ++ if (state[0].set) /* uuid */ + { + int found_uuid; + grub_cryptodisk_t dev; +@@ -1146,7 +1157,7 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) + + check_boot = state[2].set; + search_uuid = args[0]; +- found_uuid = grub_device_iterate (&grub_cryptodisk_scan_device, NULL); ++ found_uuid = grub_device_iterate (&grub_cryptodisk_scan_device, &cargs); + search_uuid = NULL; + + if (found_uuid) +@@ -1163,11 +1174,11 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) + } + return grub_errno; + } +- else if (state[1].set || (argc == 0 && state[2].set)) ++ else if (state[1].set || (argc == 0 && state[2].set)) /* -a|-b */ + { + search_uuid = NULL; + check_boot = state[2].set; +- grub_device_iterate (&grub_cryptodisk_scan_device, NULL); ++ grub_device_iterate (&grub_cryptodisk_scan_device, &cargs); + search_uuid = NULL; + return GRUB_ERR_NONE; + } +@@ -1208,7 +1219,7 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) + return GRUB_ERR_NONE; + } + +- dev = grub_cryptodisk_scan_device_real (diskname, disk); ++ dev = grub_cryptodisk_scan_device_real (diskname, disk, &cargs); + + grub_disk_close (disk); + if (disklast) +@@ -1347,7 +1358,7 @@ GRUB_MOD_INIT (cryptodisk) + { + grub_disk_dev_register (&grub_cryptodisk_dev); + cmd = grub_register_extcmd ("cryptomount", grub_cmd_cryptomount, 0, +- N_("SOURCE|-u UUID|-a|-b"), ++ N_("[-p password] "), + N_("Mount a crypto device."), options); + grub_procfs_register ("luks_script", &luks_script); + } +diff --git a/grub-core/disk/geli.c b/grub-core/disk/geli.c +index 2f34a35e6b..777da3a055 100644 +--- a/grub-core/disk/geli.c ++++ b/grub-core/disk/geli.c +@@ -398,7 +398,7 @@ configure_ciphers (grub_disk_t disk, const char *check_uuid, + } + + static grub_err_t +-recover_key (grub_disk_t source, grub_cryptodisk_t dev) ++recover_key (grub_disk_t source, grub_cryptodisk_t dev, grub_cryptomount_args_t cargs) + { + grub_size_t keysize; + grub_uint8_t digest[GRUB_CRYPTO_MAX_MDLEN]; +@@ -414,6 +414,10 @@ recover_key (grub_disk_t source, grub_cryptodisk_t dev) + grub_disk_addr_t sector; + grub_err_t err; + ++ /* Keyfiles are not implemented yet */ ++ if (cargs->key_data != NULL || cargs->key_len) ++ return GRUB_ERR_NOT_IMPLEMENTED_YET; ++ + if (dev->cipher->cipher->blocksize > GRUB_CRYPTO_MAX_CIPHER_BLOCKSIZE) + return grub_error (GRUB_ERR_BUG, "cipher block is too long"); + +diff --git a/grub-core/disk/luks.c b/grub-core/disk/luks.c +index 13103ea6a2..c5858fcf8a 100644 +--- a/grub-core/disk/luks.c ++++ b/grub-core/disk/luks.c +@@ -152,7 +152,8 @@ configure_ciphers (grub_disk_t disk, const char *check_uuid, + + static grub_err_t + luks_recover_key (grub_disk_t source, +- grub_cryptodisk_t dev) ++ grub_cryptodisk_t dev, ++ grub_cryptomount_args_t cargs) + { + struct grub_luks_phdr header; + grub_size_t keysize; +@@ -165,6 +166,10 @@ luks_recover_key (grub_disk_t source, + grub_size_t max_stripes = 1; + char *tmp; + ++ /* Keyfiles are not implemented yet */ ++ if (cargs->key_data != NULL || cargs->key_len) ++ return GRUB_ERR_NOT_IMPLEMENTED_YET; ++ + err = grub_disk_read (source, 0, 0, sizeof (header), &header); + if (err) + return err; +diff --git a/grub-core/disk/luks2.c b/grub-core/disk/luks2.c +index fea196dd4a..2cbec8acc2 100644 +--- a/grub-core/disk/luks2.c ++++ b/grub-core/disk/luks2.c +@@ -545,7 +545,8 @@ luks2_decrypt_key (grub_uint8_t *out_key, + + static grub_err_t + luks2_recover_key (grub_disk_t source, +- grub_cryptodisk_t crypt) ++ grub_cryptodisk_t crypt, ++ grub_cryptomount_args_t cargs) + { + grub_uint8_t candidate_key[GRUB_CRYPTODISK_MAX_KEYLEN]; + char passphrase[MAX_PASSPHRASE], cipher[32]; +@@ -559,6 +560,10 @@ luks2_recover_key (grub_disk_t source, + grub_json_t *json = NULL, keyslots; + grub_err_t ret; + ++ /* Keyfiles are not implemented yet */ ++ if (cargs->key_data != NULL || cargs->key_len) ++ return GRUB_ERR_NOT_IMPLEMENTED_YET; ++ + ret = luks2_read_header (source, &header); + if (ret) + return ret; +diff --git a/include/grub/cryptodisk.h b/include/grub/cryptodisk.h +index dcf17fbb3a..282f8ac456 100644 +--- a/include/grub/cryptodisk.h ++++ b/include/grub/cryptodisk.h +@@ -66,6 +66,13 @@ typedef gcry_err_code_t + (*grub_cryptodisk_rekey_func_t) (struct grub_cryptodisk *dev, + grub_uint64_t zoneno); + ++struct grub_cryptomount_args ++{ ++ grub_uint8_t *key_data; ++ grub_size_t key_len; ++}; ++typedef struct grub_cryptomount_args *grub_cryptomount_args_t; ++ + struct grub_cryptodisk + { + struct grub_cryptodisk *next; +@@ -119,7 +126,7 @@ struct grub_cryptodisk_dev + + grub_cryptodisk_t (*scan) (grub_disk_t disk, const char *check_uuid, + int boot_only); +- grub_err_t (*recover_key) (grub_disk_t disk, grub_cryptodisk_t dev); ++ grub_err_t (*recover_key) (grub_disk_t disk, grub_cryptodisk_t dev, grub_cryptomount_args_t cargs); + }; + typedef struct grub_cryptodisk_dev *grub_cryptodisk_dev_t; + +-- +2.34.1 + diff --git a/0007-cryptodisk-Refactor-password-input-out-of-crypto-dev.patch b/0007-cryptodisk-Refactor-password-input-out-of-crypto-dev.patch new file mode 100644 index 0000000..8f93c9a --- /dev/null +++ b/0007-cryptodisk-Refactor-password-input-out-of-crypto-dev.patch @@ -0,0 +1,342 @@ +From a3ae3f800f6aa3f6036351133ed69fa47c9fa371 Mon Sep 17 00:00:00 2001 +From: Glenn Washburn +Date: Thu, 9 Dec 2021 11:14:56 -0600 +Subject: [PATCH 07/14] cryptodisk: Refactor password input out of crypto dev + modules into cryptodisk + +The crypto device modules should only be setting up the crypto devices and +not getting user input. This has the added benefit of simplifying the code +such that three essentially duplicate pieces of code are merged into one. + +Add documentation of passphrase option for cryptomount as it is now usable. + +Signed-off-by: Glenn Washburn +Reviewed-by: Daniel Kiper +--- + docs/grub.texi | 8 ++++-- + grub-core/disk/cryptodisk.c | 56 +++++++++++++++++++++++++++++-------- + grub-core/disk/geli.c | 26 ++++------------- + grub-core/disk/luks.c | 27 +++--------------- + grub-core/disk/luks2.c | 25 +++-------------- + include/grub/cryptodisk.h | 1 + + 6 files changed, 64 insertions(+), 79 deletions(-) + +diff --git a/docs/grub.texi b/docs/grub.texi +index f4794fddac..4504bcabec 100644 +--- a/docs/grub.texi ++++ b/docs/grub.texi +@@ -4310,9 +4310,11 @@ Alias for @code{hashsum --hash crc32 arg @dots{}}. See command @command{hashsum} + @node cryptomount + @subsection cryptomount + +-@deffn Command cryptomount device|@option{-u} uuid|@option{-a}|@option{-b} +-Setup access to encrypted device. If necessary, passphrase +-is requested interactively. Option @var{device} configures specific grub device ++@deffn Command cryptomount [@option{-p} password] device|@option{-u} uuid|@option{-a}|@option{-b} ++Setup access to encrypted device. If @option{-p} is not given, a passphrase ++is requested interactively. Otherwise, the given @var{password} will be used and ++no passphrase will be requested interactively. ++Option @var{device} configures specific grub device + (@pxref{Naming convention}); option @option{-u} @var{uuid} configures device + with specified @var{uuid}; option @option{-a} configures all detected encrypted + devices; option @option{-b} configures all geli containers that have boot flag set. +diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c +index 14c661a86e..d12368a1f7 100644 +--- a/grub-core/disk/cryptodisk.c ++++ b/grub-core/disk/cryptodisk.c +@@ -1001,9 +1001,11 @@ grub_cryptodisk_scan_device_real (const char *name, + grub_disk_t source, + grub_cryptomount_args_t cargs) + { +- grub_err_t err; ++ grub_err_t ret = GRUB_ERR_NONE; + grub_cryptodisk_t dev; + grub_cryptodisk_dev_t cr; ++ int askpass = 0; ++ char *part = NULL; + + dev = grub_cryptodisk_get_by_source_disk (source); + +@@ -1017,21 +1019,53 @@ grub_cryptodisk_scan_device_real (const char *name, + return NULL; + if (!dev) + continue; +- +- err = cr->recover_key (source, dev, cargs); +- if (err) +- { +- cryptodisk_close (dev); +- return NULL; +- } ++ ++ if (!cargs->key_len) ++ { ++ /* Get the passphrase from the user, if no key data. */ ++ askpass = 1; ++ if (source->partition != NULL) ++ part = grub_partition_get_name (source->partition); ++ grub_printf_ (N_("Enter passphrase for %s%s%s (%s): "), source->name, ++ source->partition != NULL ? "," : "", ++ part != NULL ? part : "", ++ dev->uuid); ++ grub_free (part); ++ ++ cargs->key_data = grub_malloc (GRUB_CRYPTODISK_MAX_PASSPHRASE); ++ if (cargs->key_data == NULL) ++ return NULL; ++ ++ if (!grub_password_get ((char *) cargs->key_data, GRUB_CRYPTODISK_MAX_PASSPHRASE)) ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, "passphrase not supplied"); ++ goto error; ++ } ++ cargs->key_len = grub_strlen ((char *) cargs->key_data); ++ } ++ ++ ret = cr->recover_key (source, dev, cargs); ++ if (ret != GRUB_ERR_NONE) ++ goto error; + + grub_cryptodisk_insert (dev, name, source); + +- return dev; ++ goto cleanup; + } +- + grub_error (GRUB_ERR_BAD_MODULE, "no cryptodisk module can handle this device"); +- return NULL; ++ goto cleanup; ++ ++ error: ++ cryptodisk_close (dev); ++ dev = NULL; ++ ++ cleanup: ++ if (askpass) ++ { ++ cargs->key_len = 0; ++ grub_free (cargs->key_data); ++ } ++ return dev; + } + + #ifdef GRUB_UTIL +diff --git a/grub-core/disk/geli.c b/grub-core/disk/geli.c +index 777da3a055..7299a47d19 100644 +--- a/grub-core/disk/geli.c ++++ b/grub-core/disk/geli.c +@@ -135,8 +135,6 @@ const char *algorithms[] = { + [0x16] = "aes" + }; + +-#define MAX_PASSPHRASE 256 +- + static gcry_err_code_t + geli_rekey (struct grub_cryptodisk *dev, grub_uint64_t zoneno) + { +@@ -406,17 +404,14 @@ recover_key (grub_disk_t source, grub_cryptodisk_t dev, grub_cryptomount_args_t + grub_uint8_t verify_key[GRUB_CRYPTO_MAX_MDLEN]; + grub_uint8_t zero[GRUB_CRYPTO_MAX_CIPHER_BLOCKSIZE]; + grub_uint8_t geli_cipher_key[64]; +- char passphrase[MAX_PASSPHRASE] = ""; + unsigned i; + gcry_err_code_t gcry_err; + struct grub_geli_phdr header; +- char *tmp; + grub_disk_addr_t sector; + grub_err_t err; + +- /* Keyfiles are not implemented yet */ +- if (cargs->key_data != NULL || cargs->key_len) +- return GRUB_ERR_NOT_IMPLEMENTED_YET; ++ if (cargs->key_data == NULL || cargs->key_len == 0) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "no key data"); + + if (dev->cipher->cipher->blocksize > GRUB_CRYPTO_MAX_CIPHER_BLOCKSIZE) + return grub_error (GRUB_ERR_BUG, "cipher block is too long"); +@@ -438,23 +433,12 @@ recover_key (grub_disk_t source, grub_cryptodisk_t dev, grub_cryptomount_args_t + + grub_puts_ (N_("Attempting to decrypt master key...")); + +- /* Get the passphrase from the user. */ +- tmp = NULL; +- if (source->partition) +- tmp = grub_partition_get_name (source->partition); +- grub_printf_ (N_("Enter passphrase for %s%s%s (%s): "), source->name, +- source->partition ? "," : "", tmp ? : "", +- dev->uuid); +- grub_free (tmp); +- if (!grub_password_get (passphrase, MAX_PASSPHRASE)) +- return grub_error (GRUB_ERR_BAD_ARGUMENT, "Passphrase not supplied"); +- + /* Calculate the PBKDF2 of the user supplied passphrase. */ + if (grub_le_to_cpu32 (header.niter) != 0) + { + grub_uint8_t pbkdf_key[64]; +- gcry_err = grub_crypto_pbkdf2 (dev->hash, (grub_uint8_t *) passphrase, +- grub_strlen (passphrase), ++ gcry_err = grub_crypto_pbkdf2 (dev->hash, cargs->key_data, ++ cargs->key_len, + header.salt, + sizeof (header.salt), + grub_le_to_cpu32 (header.niter), +@@ -477,7 +461,7 @@ recover_key (grub_disk_t source, grub_cryptodisk_t dev, grub_cryptomount_args_t + return grub_crypto_gcry_error (GPG_ERR_OUT_OF_MEMORY); + + grub_crypto_hmac_write (hnd, header.salt, sizeof (header.salt)); +- grub_crypto_hmac_write (hnd, passphrase, grub_strlen (passphrase)); ++ grub_crypto_hmac_write (hnd, cargs->key_data, cargs->key_len); + + gcry_err = grub_crypto_hmac_fini (hnd, geomkey); + if (gcry_err) +diff --git a/grub-core/disk/luks.c b/grub-core/disk/luks.c +index c5858fcf8a..39a7af6a43 100644 +--- a/grub-core/disk/luks.c ++++ b/grub-core/disk/luks.c +@@ -29,8 +29,6 @@ + + GRUB_MOD_LICENSE ("GPLv3+"); + +-#define MAX_PASSPHRASE 256 +- + #define LUKS_KEY_ENABLED 0x00AC71F3 + + /* On disk LUKS header */ +@@ -158,17 +156,14 @@ luks_recover_key (grub_disk_t source, + struct grub_luks_phdr header; + grub_size_t keysize; + grub_uint8_t *split_key = NULL; +- char passphrase[MAX_PASSPHRASE] = ""; + grub_uint8_t candidate_digest[sizeof (header.mkDigest)]; + unsigned i; + grub_size_t length; + grub_err_t err; + grub_size_t max_stripes = 1; +- char *tmp; + +- /* Keyfiles are not implemented yet */ +- if (cargs->key_data != NULL || cargs->key_len) +- return GRUB_ERR_NOT_IMPLEMENTED_YET; ++ if (cargs->key_data == NULL || cargs->key_len == 0) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "no key data"); + + err = grub_disk_read (source, 0, 0, sizeof (header), &header); + if (err) +@@ -188,20 +183,6 @@ luks_recover_key (grub_disk_t source, + if (!split_key) + return grub_errno; + +- /* Get the passphrase from the user. */ +- tmp = NULL; +- if (source->partition) +- tmp = grub_partition_get_name (source->partition); +- grub_printf_ (N_("Enter passphrase for %s%s%s (%s): "), source->name, +- source->partition ? "," : "", tmp ? : "", +- dev->uuid); +- grub_free (tmp); +- if (!grub_password_get (passphrase, MAX_PASSPHRASE)) +- { +- grub_free (split_key); +- return grub_error (GRUB_ERR_BAD_ARGUMENT, "Passphrase not supplied"); +- } +- + /* Try to recover master key from each active keyslot. */ + for (i = 0; i < ARRAY_SIZE (header.keyblock); i++) + { +@@ -216,8 +197,8 @@ luks_recover_key (grub_disk_t source, + grub_dprintf ("luks", "Trying keyslot %d\n", i); + + /* Calculate the PBKDF2 of the user supplied passphrase. */ +- gcry_err = grub_crypto_pbkdf2 (dev->hash, (grub_uint8_t *) passphrase, +- grub_strlen (passphrase), ++ gcry_err = grub_crypto_pbkdf2 (dev->hash, cargs->key_data, ++ cargs->key_len, + header.keyblock[i].passwordSalt, + sizeof (header.keyblock[i].passwordSalt), + grub_be_to_cpu32 (header.keyblock[i]. +diff --git a/grub-core/disk/luks2.c b/grub-core/disk/luks2.c +index 2cbec8acc2..09740b53f9 100644 +--- a/grub-core/disk/luks2.c ++++ b/grub-core/disk/luks2.c +@@ -35,8 +35,6 @@ GRUB_MOD_LICENSE ("GPLv3+"); + #define LUKS_MAGIC_1ST "LUKS\xBA\xBE" + #define LUKS_MAGIC_2ND "SKUL\xBA\xBE" + +-#define MAX_PASSPHRASE 256 +- + enum grub_luks2_kdf_type + { + LUKS2_KDF_TYPE_ARGON2I, +@@ -549,8 +547,7 @@ luks2_recover_key (grub_disk_t source, + grub_cryptomount_args_t cargs) + { + grub_uint8_t candidate_key[GRUB_CRYPTODISK_MAX_KEYLEN]; +- char passphrase[MAX_PASSPHRASE], cipher[32]; +- char *json_header = NULL, *part = NULL, *ptr; ++ char cipher[32], *json_header = NULL, *ptr; + grub_size_t candidate_key_len = 0, json_idx, size; + grub_luks2_header_t header; + grub_luks2_keyslot_t keyslot; +@@ -560,9 +557,8 @@ luks2_recover_key (grub_disk_t source, + grub_json_t *json = NULL, keyslots; + grub_err_t ret; + +- /* Keyfiles are not implemented yet */ +- if (cargs->key_data != NULL || cargs->key_len) +- return GRUB_ERR_NOT_IMPLEMENTED_YET; ++ if (cargs->key_data == NULL || cargs->key_len == 0) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "no key data"); + + ret = luks2_read_header (source, &header); + if (ret) +@@ -589,18 +585,6 @@ luks2_recover_key (grub_disk_t source, + goto err; + } + +- /* Get the passphrase from the user. */ +- if (source->partition) +- part = grub_partition_get_name (source->partition); +- grub_printf_ (N_("Enter passphrase for %s%s%s (%s): "), source->name, +- source->partition ? "," : "", part ? : "", +- crypt->uuid); +- if (!grub_password_get (passphrase, MAX_PASSPHRASE)) +- { +- ret = grub_error (GRUB_ERR_BAD_ARGUMENT, "Passphrase not supplied"); +- goto err; +- } +- + if (grub_json_getvalue (&keyslots, json, "keyslots") || + grub_json_getsize (&size, &keyslots)) + { +@@ -725,7 +709,7 @@ luks2_recover_key (grub_disk_t source, + } + + ret = luks2_decrypt_key (candidate_key, source, crypt, &keyslot, +- (const grub_uint8_t *) passphrase, grub_strlen (passphrase)); ++ cargs->key_data, cargs->key_len); + if (ret) + { + grub_dprintf ("luks2", "Decryption with keyslot \"%" PRIuGRUB_UINT64_T "\" failed: %s\n", +@@ -777,7 +761,6 @@ luks2_recover_key (grub_disk_t source, + } + + err: +- grub_free (part); + grub_free (json_header); + grub_json_free (json); + return ret; +diff --git a/include/grub/cryptodisk.h b/include/grub/cryptodisk.h +index 282f8ac456..5bd970692f 100644 +--- a/include/grub/cryptodisk.h ++++ b/include/grub/cryptodisk.h +@@ -59,6 +59,7 @@ typedef enum + #define GRUB_CRYPTODISK_GF_LOG_BYTES (GRUB_CRYPTODISK_GF_LOG_SIZE - 3) + #define GRUB_CRYPTODISK_GF_BYTES (1U << GRUB_CRYPTODISK_GF_LOG_BYTES) + #define GRUB_CRYPTODISK_MAX_KEYLEN 128 ++#define GRUB_CRYPTODISK_MAX_PASSPHRASE 256 + + struct grub_cryptodisk; + +-- +2.34.1 + diff --git a/0008-cryptodisk-Move-global-variables-into-grub_cryptomou.patch b/0008-cryptodisk-Move-global-variables-into-grub_cryptomou.patch new file mode 100644 index 0000000..b40f35f --- /dev/null +++ b/0008-cryptodisk-Move-global-variables-into-grub_cryptomou.patch @@ -0,0 +1,248 @@ +From 5323778d84a7289acba0e50d84fb1afd45fff596 Mon Sep 17 00:00:00 2001 +From: Glenn Washburn +Date: Thu, 9 Dec 2021 11:14:57 -0600 +Subject: [PATCH 08/14] cryptodisk: Move global variables into + grub_cryptomount_args struct + +Note that cargs.search_uuid does not need to be initialized in various parts +of the cryptomount argument parsing, just once when cargs is declared with +a struct initializer. The previous code used a global variable which would +retain the value across cryptomount invocations. + +Signed-off-by: Glenn Washburn +Reviewed-by: Daniel Kiper +--- + grub-core/disk/cryptodisk.c | 24 +++++++++--------------- + grub-core/disk/geli.c | 9 ++++----- + grub-core/disk/luks.c | 9 ++++----- + grub-core/disk/luks2.c | 8 ++++---- + include/grub/cryptodisk.h | 9 +++++++-- + 5 files changed, 28 insertions(+), 31 deletions(-) + +diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c +index d12368a1f7..7ca880402d 100644 +--- a/grub-core/disk/cryptodisk.c ++++ b/grub-core/disk/cryptodisk.c +@@ -984,9 +984,6 @@ grub_util_cryptodisk_get_uuid (grub_disk_t disk) + + #endif + +-static int check_boot; +-static char *search_uuid; +- + static void + cryptodisk_close (grub_cryptodisk_t dev) + { +@@ -1014,7 +1011,7 @@ grub_cryptodisk_scan_device_real (const char *name, + + FOR_CRYPTODISK_DEVS (cr) + { +- dev = cr->scan (source, search_uuid, check_boot); ++ dev = cr->scan (source, cargs); + if (grub_errno) + return NULL; + if (!dev) +@@ -1077,6 +1074,7 @@ grub_cryptodisk_cheat_mount (const char *sourcedev, const char *cheat) + grub_cryptodisk_t dev; + grub_cryptodisk_dev_t cr; + grub_disk_t source; ++ struct grub_cryptomount_args cargs = {0}; + + /* Try to open disk. */ + source = grub_disk_open (sourcedev); +@@ -1093,7 +1091,7 @@ grub_cryptodisk_cheat_mount (const char *sourcedev, const char *cheat) + + FOR_CRYPTODISK_DEVS (cr) + { +- dev = cr->scan (source, search_uuid, check_boot); ++ dev = cr->scan (source, &cargs); + if (grub_errno) + return grub_errno; + if (!dev) +@@ -1136,7 +1134,7 @@ grub_cryptodisk_scan_device (const char *name, + dev = grub_cryptodisk_scan_device_real (name, source, cargs); + if (dev) + { +- ret = (search_uuid != NULL && grub_strcasecmp (search_uuid, dev->uuid) == 0); ++ ret = (cargs->search_uuid != NULL && grub_strcasecmp (cargs->search_uuid, dev->uuid) == 0); + goto cleanup; + } + +@@ -1147,7 +1145,7 @@ grub_cryptodisk_scan_device (const char *name, + if (grub_errno == GRUB_ERR_BAD_MODULE) + grub_error_pop (); + +- if (search_uuid != NULL) ++ if (cargs->search_uuid != NULL) + /* Push error onto stack to save for cryptomount. */ + grub_error_push (); + else +@@ -1189,10 +1187,9 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) + return GRUB_ERR_NONE; + } + +- check_boot = state[2].set; +- search_uuid = args[0]; ++ cargs.check_boot = state[2].set; ++ cargs.search_uuid = args[0]; + found_uuid = grub_device_iterate (&grub_cryptodisk_scan_device, &cargs); +- search_uuid = NULL; + + if (found_uuid) + return GRUB_ERR_NONE; +@@ -1210,10 +1207,8 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) + } + else if (state[1].set || (argc == 0 && state[2].set)) /* -a|-b */ + { +- search_uuid = NULL; +- check_boot = state[2].set; ++ cargs.check_boot = state[2].set; + grub_device_iterate (&grub_cryptodisk_scan_device, &cargs); +- search_uuid = NULL; + return GRUB_ERR_NONE; + } + else +@@ -1224,8 +1219,7 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) + char *disklast = NULL; + grub_size_t len; + +- search_uuid = NULL; +- check_boot = state[2].set; ++ cargs.check_boot = state[2].set; + diskname = args[0]; + len = grub_strlen (diskname); + if (len && diskname[0] == '(' && diskname[len - 1] == ')') +diff --git a/grub-core/disk/geli.c b/grub-core/disk/geli.c +index 7299a47d19..23789c43f3 100644 +--- a/grub-core/disk/geli.c ++++ b/grub-core/disk/geli.c +@@ -240,8 +240,7 @@ grub_util_get_geli_uuid (const char *dev) + #endif + + static grub_cryptodisk_t +-configure_ciphers (grub_disk_t disk, const char *check_uuid, +- int boot_only) ++configure_ciphers (grub_disk_t disk, grub_cryptomount_args_t cargs) + { + grub_cryptodisk_t newdev; + struct grub_geli_phdr header; +@@ -289,7 +288,7 @@ configure_ciphers (grub_disk_t disk, const char *check_uuid, + return NULL; + } + +- if (boot_only && !(grub_le_to_cpu32 (header.flags) & GRUB_GELI_FLAGS_BOOT)) ++ if (cargs->check_boot && !(grub_le_to_cpu32 (header.flags) & GRUB_GELI_FLAGS_BOOT)) + { + grub_dprintf ("geli", "not a boot volume\n"); + return NULL; +@@ -302,9 +301,9 @@ configure_ciphers (grub_disk_t disk, const char *check_uuid, + return NULL; + } + +- if (check_uuid && grub_strcasecmp (check_uuid, uuid) != 0) ++ if (cargs->search_uuid != NULL && grub_strcasecmp (cargs->search_uuid, uuid) != 0) + { +- grub_dprintf ("geli", "%s != %s\n", uuid, check_uuid); ++ grub_dprintf ("geli", "%s != %s\n", uuid, cargs->search_uuid); + return NULL; + } + +diff --git a/grub-core/disk/luks.c b/grub-core/disk/luks.c +index 39a7af6a43..f0feb38447 100644 +--- a/grub-core/disk/luks.c ++++ b/grub-core/disk/luks.c +@@ -63,8 +63,7 @@ gcry_err_code_t AF_merge (const gcry_md_spec_t * hash, grub_uint8_t * src, + grub_size_t blocknumbers); + + static grub_cryptodisk_t +-configure_ciphers (grub_disk_t disk, const char *check_uuid, +- int check_boot) ++configure_ciphers (grub_disk_t disk, grub_cryptomount_args_t cargs) + { + grub_cryptodisk_t newdev; + const char *iptr; +@@ -76,7 +75,7 @@ configure_ciphers (grub_disk_t disk, const char *check_uuid, + char hashspec[sizeof (header.hashSpec) + 1]; + grub_err_t err; + +- if (check_boot) ++ if (cargs->check_boot) + return NULL; + + /* Read the LUKS header. */ +@@ -103,9 +102,9 @@ configure_ciphers (grub_disk_t disk, const char *check_uuid, + } + *optr = 0; + +- if (check_uuid && grub_strcasecmp (check_uuid, uuid) != 0) ++ if (cargs->search_uuid != NULL && grub_strcasecmp (cargs->search_uuid, uuid) != 0) + { +- grub_dprintf ("luks", "%s != %s\n", uuid, check_uuid); ++ grub_dprintf ("luks", "%s != %s\n", uuid, cargs->search_uuid); + return NULL; + } + +diff --git a/grub-core/disk/luks2.c b/grub-core/disk/luks2.c +index 09740b53f9..ccfacb63a3 100644 +--- a/grub-core/disk/luks2.c ++++ b/grub-core/disk/luks2.c +@@ -346,14 +346,14 @@ luks2_read_header (grub_disk_t disk, grub_luks2_header_t *outhdr) + } + + static grub_cryptodisk_t +-luks2_scan (grub_disk_t disk, const char *check_uuid, int check_boot) ++luks2_scan (grub_disk_t disk, grub_cryptomount_args_t cargs) + { + grub_cryptodisk_t cryptodisk; + grub_luks2_header_t header; + char uuid[sizeof (header.uuid) + 1]; + grub_size_t i, j; + +- if (check_boot) ++ if (cargs->check_boot) + return NULL; + + if (luks2_read_header (disk, &header)) +@@ -367,9 +367,9 @@ luks2_scan (grub_disk_t disk, const char *check_uuid, int check_boot) + uuid[j++] = header.uuid[i]; + uuid[j] = '\0'; + +- if (check_uuid && grub_strcasecmp (check_uuid, uuid) != 0) ++ if (cargs->search_uuid != NULL && grub_strcasecmp (cargs->search_uuid, uuid) != 0) + { +- grub_dprintf ("luks2", "%s != %s\n", uuid, check_uuid); ++ grub_dprintf ("luks2", "%s != %s\n", uuid, cargs->search_uuid); + return NULL; + } + +diff --git a/include/grub/cryptodisk.h b/include/grub/cryptodisk.h +index 5bd970692f..c6524c9ea9 100644 +--- a/include/grub/cryptodisk.h ++++ b/include/grub/cryptodisk.h +@@ -69,7 +69,13 @@ typedef gcry_err_code_t + + struct grub_cryptomount_args + { ++ /* scan: Flag to indicate that only bootable volumes should be decrypted */ ++ grub_uint32_t check_boot : 1; ++ /* scan: Only volumes matching this UUID should be decrpyted */ ++ char *search_uuid; ++ /* recover_key: Key data used to decrypt voume */ + grub_uint8_t *key_data; ++ /* recover_key: Length of key_data */ + grub_size_t key_len; + }; + typedef struct grub_cryptomount_args *grub_cryptomount_args_t; +@@ -125,8 +131,7 @@ struct grub_cryptodisk_dev + struct grub_cryptodisk_dev *next; + struct grub_cryptodisk_dev **prev; + +- grub_cryptodisk_t (*scan) (grub_disk_t disk, const char *check_uuid, +- int boot_only); ++ grub_cryptodisk_t (*scan) (grub_disk_t disk, grub_cryptomount_args_t cargs); + grub_err_t (*recover_key) (grub_disk_t disk, grub_cryptodisk_t dev, grub_cryptomount_args_t cargs); + }; + typedef struct grub_cryptodisk_dev *grub_cryptodisk_dev_t; +-- +2.34.1 + diff --git a/0009-cryptodisk-Improve-handling-of-partition-name-in-cry.patch b/0009-cryptodisk-Improve-handling-of-partition-name-in-cry.patch new file mode 100644 index 0000000..834f7e9 --- /dev/null +++ b/0009-cryptodisk-Improve-handling-of-partition-name-in-cry.patch @@ -0,0 +1,39 @@ +From b1acd971fa648fa3c6f3a54db4fdf45fae02ce54 Mon Sep 17 00:00:00 2001 +From: Glenn Washburn +Date: Thu, 9 Dec 2021 11:14:58 -0600 +Subject: [PATCH 09/14] cryptodisk: Improve handling of partition name in + cryptomount password prompt + +Call grub_partition_get_name() unconditionally to initialize the part +variable. Then part will only be NULL when grub_partition_get_name() errors. +Note that when source->partition is NULL, then grub_partition_get_name() +returns an allocated empty string. So no comma or partition will be printed, +as desired. + +Signed-off-by: Glenn Washburn +Reviewed-by: Daniel Kiper +--- + grub-core/disk/cryptodisk.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c +index 7ca880402d..497097394f 100644 +--- a/grub-core/disk/cryptodisk.c ++++ b/grub-core/disk/cryptodisk.c +@@ -1021,11 +1021,10 @@ grub_cryptodisk_scan_device_real (const char *name, + { + /* Get the passphrase from the user, if no key data. */ + askpass = 1; +- if (source->partition != NULL) +- part = grub_partition_get_name (source->partition); ++ part = grub_partition_get_name (source->partition); + grub_printf_ (N_("Enter passphrase for %s%s%s (%s): "), source->name, + source->partition != NULL ? "," : "", +- part != NULL ? part : "", ++ part != NULL ? part : N_("UNKNOWN"), + dev->uuid); + grub_free (part); + +-- +2.34.1 + diff --git a/0010-protectors-Add-key-protectors-framework.patch b/0010-protectors-Add-key-protectors-framework.patch new file mode 100644 index 0000000..84a5612 --- /dev/null +++ b/0010-protectors-Add-key-protectors-framework.patch @@ -0,0 +1,189 @@ +From 2d959549857305d5e4d95a19a0850885f85179d6 Mon Sep 17 00:00:00 2001 +From: Hernan Gatta +Date: Tue, 1 Feb 2022 05:02:53 -0800 +Subject: [PATCH 10/14] protectors: Add key protectors framework + +A key protector encapsulates functionality to retrieve an unlocking key for a +fully-encrypted disk from a specific source. A key protector module registers +itself with the key protectors framework when it is loaded and unregisters when +unloaded. Additionally, a key protector may accept parameters that describe how +it should operate. + +The key protectors framework, besides offering registration and unregistration +functions, also offers a one-stop routine for finding and invoking a key +protector by name. If a key protector with the specified name exists and if an +unlocking key is successfully retrieved by it, the function returns to the +caller the retrieved key and its length. + +Signed-off-by: Hernan Gatta +--- + grub-core/Makefile.am | 1 + + grub-core/Makefile.core.def | 1 + + grub-core/kern/protectors.c | 75 +++++++++++++++++++++++++++++++++++++ + include/grub/protector.h | 48 ++++++++++++++++++++++++ + 4 files changed, 125 insertions(+) + create mode 100644 grub-core/kern/protectors.c + create mode 100644 include/grub/protector.h + +diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am +index de241f0d04..dc07ba6f87 100644 +--- a/grub-core/Makefile.am ++++ b/grub-core/Makefile.am +@@ -90,6 +90,7 @@ endif + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/mm.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/parser.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/partition.h ++KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/protector.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/stack_protector.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/term.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/time.h +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index f3140815b8..b0001a33cf 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -138,6 +138,7 @@ kernel = { + common = kern/misc.c; + common = kern/parser.c; + common = kern/partition.c; ++ common = kern/protectors.c; + common = kern/rescue_parser.c; + common = kern/rescue_reader.c; + common = kern/term.c; +diff --git a/grub-core/kern/protectors.c b/grub-core/kern/protectors.c +new file mode 100644 +index 0000000000..21954dfa48 +--- /dev/null ++++ b/grub-core/kern/protectors.c +@@ -0,0 +1,75 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2022 Microsoft Corporation ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++#include ++#include ++#include ++ ++struct grub_key_protector *grub_key_protectors = NULL; ++ ++grub_err_t ++grub_key_protector_register (struct grub_key_protector *protector) ++{ ++ if (!protector || !protector->name || !grub_strlen(protector->name)) ++ return GRUB_ERR_BAD_ARGUMENT; ++ ++ if (grub_key_protectors && ++ grub_named_list_find (GRUB_AS_NAMED_LIST (grub_key_protectors), ++ protector->name)) ++ return GRUB_ERR_BAD_ARGUMENT; ++ ++ grub_list_push (GRUB_AS_LIST_P (&grub_key_protectors), ++ GRUB_AS_LIST (protector)); ++ ++ return GRUB_ERR_NONE; ++} ++ ++grub_err_t ++grub_key_protector_unregister (struct grub_key_protector *protector) ++{ ++ if (!protector) ++ return GRUB_ERR_BAD_ARGUMENT; ++ ++ grub_list_remove (GRUB_AS_LIST (protector)); ++ ++ return GRUB_ERR_NONE; ++} ++ ++grub_err_t ++grub_key_protector_recover_key (const char *protector, grub_uint8_t **key, ++ grub_size_t *key_size) ++{ ++ struct grub_key_protector *kp = NULL; ++ ++ if (!grub_key_protectors) ++ return GRUB_ERR_OUT_OF_RANGE; ++ ++ if (!protector || !grub_strlen (protector)) ++ return GRUB_ERR_BAD_ARGUMENT; ++ ++ kp = grub_named_list_find (GRUB_AS_NAMED_LIST (grub_key_protectors), ++ protector); ++ if (!kp) ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, ++ N_("A key protector with name '%s' could not be found. " ++ "Is the name spelled correctly and is the " ++ "corresponding module loaded?"), protector); ++ ++ return kp->recover_key (key, key_size); ++} +diff --git a/include/grub/protector.h b/include/grub/protector.h +new file mode 100644 +index 0000000000..179020a344 +--- /dev/null ++++ b/include/grub/protector.h +@@ -0,0 +1,48 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2022 Microsoft Corporation ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#ifndef GRUB_PROTECTOR_HEADER ++#define GRUB_PROTECTOR_HEADER 1 ++ ++#include ++#include ++ ++struct grub_key_protector ++{ ++ struct grub_key_protector *next; ++ struct grub_key_protector **prev; ++ ++ const char *name; ++ ++ grub_err_t (*recover_key) (grub_uint8_t **key, grub_size_t *key_size); ++}; ++ ++extern struct grub_key_protector *EXPORT_VAR (grub_key_protectors); ++ ++grub_err_t ++EXPORT_FUNC (grub_key_protector_register) (struct grub_key_protector *protector); ++ ++grub_err_t ++EXPORT_FUNC (grub_key_protector_unregister) (struct grub_key_protector *protector); ++ ++grub_err_t ++EXPORT_FUNC (grub_key_protector_recover_key) (const char *protector, ++ grub_uint8_t **key, ++ grub_size_t *key_size); ++ ++#endif /* ! GRUB_PROTECTOR_HEADER */ +-- +2.34.1 + diff --git a/0011-tpm2-Add-TPM-Software-Stack-TSS.patch b/0011-tpm2-Add-TPM-Software-Stack-TSS.patch new file mode 100644 index 0000000..9c0755c --- /dev/null +++ b/0011-tpm2-Add-TPM-Software-Stack-TSS.patch @@ -0,0 +1,3523 @@ +From 65f937752d51b81fb830d4c6177975d395be9346 Mon Sep 17 00:00:00 2001 +From: Hernan Gatta +Date: Tue, 1 Feb 2022 05:02:54 -0800 +Subject: [PATCH 11/14] tpm2: Add TPM Software Stack (TSS) + +A Trusted Platform Module (TPM) Software Stack (TSS) provides logic to compose, +submit, and parse TPM commands and responses. + +A limited number of TPM commands may be accessed via the EFI TCG2 protocol. This +protocol exposes functionality that is primarily geared toward TPM usage within +the context of Secure Boot. For all other TPM commands, however, such as sealing +and unsealing, this protocol does not provide any help, with the exception of +passthrough command submission. + +The SubmitCommand method allows a caller to send raw commands to the system's +TPM and to receive the corresponding response. These command/response pairs are +formatted using the TPM wire protocol. To construct commands in this way, and to +parse the TPM's response, it is necessary to, first, possess knowledge of the +various TPM structures, and, two, of the TPM wire protocol itself. + +As such, this patch includes a set of header files that define the necessary TPM +structures and TSS functions, implementations of various TPM2_* functions +(inventoried below), and logic to write and read command and response buffers, +respectively, using the TPM wire protocol. + +Functions: TPM2_Create, TPM2_CreatePrimary, TPM2_EvictControl, +TPM2_FlushContext, TPM2_Load, TPM2_PCR_Read, TPM2_PolicyGetDigest, +TPM2_PolicyPCR, TPM2_ReadPublic, TPM2_StartAuthSession, TPM2_Unseal. + +Signed-off-by: Hernan Gatta +--- + grub-core/tpm2/buffer.c | 145 +++++ + grub-core/tpm2/mu.c | 807 +++++++++++++++++++++++++ + grub-core/tpm2/tcg2.c | 143 +++++ + grub-core/tpm2/tpm2.c | 711 ++++++++++++++++++++++ + include/grub/tpm2/buffer.h | 65 ++ + include/grub/tpm2/internal/functions.h | 117 ++++ + include/grub/tpm2/internal/structs.h | 675 +++++++++++++++++++++ + include/grub/tpm2/internal/types.h | 372 ++++++++++++ + include/grub/tpm2/mu.h | 292 +++++++++ + include/grub/tpm2/tcg2.h | 34 ++ + include/grub/tpm2/tpm2.h | 38 ++ + 11 files changed, 3399 insertions(+) + create mode 100644 grub-core/tpm2/buffer.c + create mode 100644 grub-core/tpm2/mu.c + create mode 100644 grub-core/tpm2/tcg2.c + create mode 100644 grub-core/tpm2/tpm2.c + create mode 100644 include/grub/tpm2/buffer.h + create mode 100644 include/grub/tpm2/internal/functions.h + create mode 100644 include/grub/tpm2/internal/structs.h + create mode 100644 include/grub/tpm2/internal/types.h + create mode 100644 include/grub/tpm2/mu.h + create mode 100644 include/grub/tpm2/tcg2.h + create mode 100644 include/grub/tpm2/tpm2.h + +diff --git a/grub-core/tpm2/buffer.c b/grub-core/tpm2/buffer.c +new file mode 100644 +index 0000000000..fee42d5a9e +--- /dev/null ++++ b/grub-core/tpm2/buffer.c +@@ -0,0 +1,145 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2022 Microsoft Corporation ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++#include ++ ++void grub_tpm2_buffer_init (grub_tpm2_buffer_t buffer) ++{ ++ grub_memset (buffer->data, 0xDD, sizeof (buffer->data)); ++ buffer->size = 0; ++ buffer->offset = 0; ++ buffer->cap = sizeof (buffer->data); ++ buffer->error = 0; ++} ++ ++void ++grub_tpm2_buffer_pack (grub_tpm2_buffer_t buffer, const void* data, ++ grub_size_t size) ++{ ++ grub_uint32_t r = buffer->cap - buffer->size; ++ ++ if (buffer->error) ++ return; ++ ++ if (size > r) ++ { ++ buffer->error = 1; ++ return; ++ } ++ ++ grub_memcpy (&buffer->data[buffer->size], (void*) data, size); ++ buffer->size += size; ++} ++ ++void ++grub_tpm2_buffer_pack_u8 (grub_tpm2_buffer_t buffer, grub_uint8_t value) ++{ ++ grub_tpm2_buffer_pack (buffer, (const char*) &value, sizeof (value)); ++} ++ ++void ++grub_tpm2_buffer_pack_u16 (grub_tpm2_buffer_t buffer, grub_uint16_t value) ++{ ++ grub_uint16_t tmp = grub_swap_bytes16 (value); ++ grub_tpm2_buffer_pack (buffer, (const char*) &tmp, sizeof (tmp)); ++} ++ ++void ++grub_tpm2_buffer_pack_u32 (grub_tpm2_buffer_t buffer, grub_uint32_t value) ++{ ++ grub_uint32_t tmp = grub_swap_bytes32 (value); ++ grub_tpm2_buffer_pack (buffer, (const char*) &tmp, sizeof (tmp)); ++} ++ ++void ++grub_tpm2_buffer_unpack (grub_tpm2_buffer_t buffer, void* data, ++ grub_size_t size) ++{ ++ grub_uint32_t r = buffer->size - buffer->offset; ++ ++ if (buffer->error) ++ return; ++ ++ if (size > r) ++ { ++ buffer->error = 1; ++ return; ++ } ++ ++ grub_memcpy (data, &buffer->data[buffer->offset], size); ++ buffer->offset += size; ++} ++ ++void ++grub_tpm2_buffer_unpack_u8 (grub_tpm2_buffer_t buffer, grub_uint8_t* value) ++{ ++ grub_uint32_t r = buffer->size - buffer->offset; ++ ++ if (buffer->error) ++ return; ++ ++ if (sizeof (*value) > r) ++ { ++ buffer->error = 1; ++ return; ++ } ++ ++ grub_memcpy (value, &buffer->data[buffer->offset], sizeof (*value)); ++ buffer->offset += sizeof (*value); ++} ++ ++void ++grub_tpm2_buffer_unpack_u16 (grub_tpm2_buffer_t buffer, grub_uint16_t* value) ++{ ++ grub_uint16_t tmp; ++ grub_uint32_t r = buffer->size - buffer->offset; ++ ++ if (buffer->error) ++ return; ++ ++ if (sizeof (tmp) > r) ++ { ++ buffer->error = 1; ++ return; ++ } ++ ++ grub_memcpy (&tmp, &buffer->data[buffer->offset], sizeof (tmp)); ++ buffer->offset += sizeof (tmp); ++ *value = grub_swap_bytes16 (tmp); ++} ++ ++void ++grub_tpm2_buffer_unpack_u32 (grub_tpm2_buffer_t buffer, grub_uint32_t* value) ++{ ++ grub_uint32_t tmp; ++ grub_uint32_t r = buffer->size - buffer->offset; ++ ++ if (buffer->error) ++ return; ++ ++ if (sizeof (tmp) > r) ++ { ++ buffer->error = 1; ++ return; ++ } ++ ++ grub_memcpy (&tmp, &buffer->data[buffer->offset], sizeof (tmp)); ++ buffer->offset += sizeof (tmp); ++ *value = grub_swap_bytes32 (tmp); ++} +diff --git a/grub-core/tpm2/mu.c b/grub-core/tpm2/mu.c +new file mode 100644 +index 0000000000..c5f5c7b5f8 +--- /dev/null ++++ b/grub-core/tpm2/mu.c +@@ -0,0 +1,807 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2022 Microsoft Corporation ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++#include ++ ++void ++grub_tpm2_mu_TPMS_AUTH_COMMAND_Marshal (grub_tpm2_buffer_t buffer, ++ const TPMS_AUTH_COMMAND* authCommand) ++{ ++ grub_uint32_t start; ++ grub_uint32_t tmp; ++ ++ grub_tpm2_buffer_pack_u32 (buffer, 0); ++ start = buffer->size; ++ ++ grub_tpm2_buffer_pack_u32 (buffer, authCommand->sessionHandle); ++ ++ grub_tpm2_buffer_pack_u16 (buffer, authCommand->nonce.size); ++ grub_tpm2_buffer_pack (buffer, authCommand->nonce.buffer, ++ authCommand->nonce.size); ++ ++ grub_tpm2_buffer_pack_u8 (buffer, ++ *((const grub_uint8_t*) &authCommand->sessionAttributes)); ++ ++ grub_tpm2_buffer_pack_u16 (buffer, authCommand->hmac.size); ++ grub_tpm2_buffer_pack (buffer, authCommand->hmac.buffer, ++ authCommand->hmac.size); ++ ++ tmp = grub_swap_bytes32 (buffer->size - start); ++ grub_memcpy (&buffer->data[start - sizeof (grub_uint32_t)], &tmp, ++ sizeof (tmp)); ++} ++ ++void ++grub_tpm2_mu_TPM2B_Marshal (grub_tpm2_buffer_t buffer, ++ grub_uint16_t size, ++ const grub_uint8_t* b) ++{ ++ grub_tpm2_buffer_pack_u16 (buffer, size); ++ ++ for (grub_uint16_t i = 0; i < size; i++) ++ grub_tpm2_buffer_pack_u8 (buffer, b[i]); ++} ++ ++void ++grub_tpm2_mu_TPMU_SYM_KEY_BITS_Marshal (grub_tpm2_buffer_t buffer, ++ TPMI_ALG_SYM_OBJECT algorithm, ++ TPMU_SYM_KEY_BITS *p) ++{ ++ switch (algorithm) ++ { ++ case TPM_ALG_AES: ++ case TPM_ALG_SM4: ++ case TPM_ALG_CAMELLIA: ++ case TPM_ALG_XOR: ++ grub_tpm2_buffer_pack_u16 (buffer, *((const grub_uint16_t*) p)); ++ break; ++ case TPM_ALG_NULL: ++ break; ++ } ++} ++ ++void ++grub_tpm2_mu_TPMU_SYM_MODE_Marshal (grub_tpm2_buffer_t buffer, ++ TPMI_ALG_SYM_OBJECT algorithm, ++ TPMU_SYM_MODE *p) ++{ ++ switch (algorithm) ++ { ++ case TPM_ALG_AES: ++ case TPM_ALG_SM4: ++ case TPM_ALG_CAMELLIA: ++ grub_tpm2_buffer_pack_u16 (buffer, *((const grub_uint16_t*) p)); ++ break; ++ case TPM_ALG_XOR: ++ case TPM_ALG_NULL: ++ break; ++ } ++} ++ ++void ++grub_tpm2_mu_TPMT_SYM_DEF_Marshal (grub_tpm2_buffer_t buffer, ++ TPMT_SYM_DEF *p) ++{ ++ grub_tpm2_buffer_pack_u16 (buffer, p->algorithm); ++ grub_tpm2_mu_TPMU_SYM_KEY_BITS_Marshal (buffer, p->algorithm, &p->keyBits); ++ grub_tpm2_mu_TPMU_SYM_MODE_Marshal (buffer, p->algorithm, &p->mode); ++} ++ ++void ++grub_tpm2_mu_TPMS_PCR_SELECTION_Marshal (grub_tpm2_buffer_t buffer, ++ const TPMS_PCR_SELECTION* pcrSelection) ++{ ++ grub_tpm2_buffer_pack_u16 (buffer, pcrSelection->hash); ++ grub_tpm2_buffer_pack_u8 (buffer, pcrSelection->sizeOfSelect); ++ ++ for (grub_uint32_t i = 0; i < pcrSelection->sizeOfSelect; i++) ++ grub_tpm2_buffer_pack_u8 (buffer, pcrSelection->pcrSelect[i]); ++} ++ ++void ++grub_tpm2_mu_TPML_PCR_SELECTION_Marshal (grub_tpm2_buffer_t buffer, ++ const TPML_PCR_SELECTION* pcrSelection) ++{ ++ grub_tpm2_buffer_pack_u32 (buffer, pcrSelection->count); ++ ++ for (grub_uint32_t i = 0; i < pcrSelection->count; i++) ++ grub_tpm2_mu_TPMS_PCR_SELECTION_Marshal (buffer, ++ &pcrSelection->pcrSelections[i]); ++} ++ ++void ++grub_tpm2_mu_TPMA_OBJECT_Marshal (grub_tpm2_buffer_t buffer, ++ const TPMA_OBJECT *p) ++{ ++ grub_tpm2_buffer_pack_u32 (buffer, *((const grub_uint32_t*) p)); ++} ++ ++void ++grub_tpm2_mu_TPMS_SCHEME_XOR_Marshal (grub_tpm2_buffer_t buffer, ++ TPMS_SCHEME_XOR *p) ++{ ++ grub_tpm2_buffer_pack_u16 (buffer, p->hashAlg); ++ grub_tpm2_buffer_pack_u16 (buffer, p->kdf); ++} ++ ++void ++grub_tpm2_mu_TPMS_SCHEME_HMAC_Marshal (grub_tpm2_buffer_t buffer, ++ TPMS_SCHEME_HMAC *p) ++{ ++ grub_tpm2_buffer_pack_u16 (buffer, p->hashAlg); ++} ++ ++void ++grub_tpm2_mu_TPMU_SCHEME_KEYEDHASH_Marshal (grub_tpm2_buffer_t buffer, ++ TPMI_ALG_KEYEDHASH_SCHEME scheme, ++ TPMU_SCHEME_KEYEDHASH *p) ++{ ++ switch (scheme) ++ { ++ case TPM_ALG_HMAC: ++ grub_tpm2_mu_TPMS_SCHEME_HMAC_Marshal (buffer, &p->hmac); ++ break; ++ case TPM_ALG_XOR: ++ grub_tpm2_mu_TPMS_SCHEME_XOR_Marshal (buffer, &p->exclusiveOr); ++ break; ++ case TPM_ALG_NULL: ++ break; ++ default: ++ buffer->error = 1; ++ break; ++ } ++} ++ ++void ++grub_tpm2_mu_TPMT_KEYEDHASH_SCHEME_Marshal (grub_tpm2_buffer_t buffer, ++ TPMT_KEYEDHASH_SCHEME *p) ++{ ++ grub_tpm2_buffer_pack_u16 (buffer, p->scheme); ++ grub_tpm2_mu_TPMU_SCHEME_KEYEDHASH_Marshal (buffer, p->scheme, &p->details); ++} ++ ++void ++grub_tpm2_mu_TPMS_KEYEDHASH_PARMS_Marshal (grub_tpm2_buffer_t buffer, ++ TPMS_KEYEDHASH_PARMS *p) ++{ ++ grub_tpm2_mu_TPMT_KEYEDHASH_SCHEME_Marshal (buffer, &p->scheme); ++} ++ ++void ++grub_tpm2_mu_TPMT_SYM_DEF_OBJECT_Marshal (grub_tpm2_buffer_t buffer, ++ TPMT_SYM_DEF_OBJECT *p) ++{ ++ grub_tpm2_buffer_pack_u16 (buffer, p->algorithm); ++ grub_tpm2_mu_TPMU_SYM_KEY_BITS_Marshal (buffer, p->algorithm, &p->keyBits); ++ grub_tpm2_mu_TPMU_SYM_MODE_Marshal (buffer, p->algorithm, &p->mode); ++} ++ ++void ++grub_tpm2_mu_TPMU_ASYM_SCHEME_Marshal (grub_tpm2_buffer_t buffer, ++ TPMI_ALG_RSA_DECRYPT scheme, ++ TPMU_ASYM_SCHEME *p __attribute__ ((unused))) ++{ ++ switch (scheme) ++ { ++ case TPM_ALG_NULL: ++ break; ++ default: ++ /* Unsupported */ ++ buffer->error = 1; ++ break; ++ } ++} ++ ++void ++grub_tpm2_mu_TPMT_RSA_SCHEME_Marshal (grub_tpm2_buffer_t buffer, ++ TPMT_RSA_SCHEME *p) ++{ ++ grub_tpm2_buffer_pack_u16 (buffer, p->scheme); ++ grub_tpm2_mu_TPMU_ASYM_SCHEME_Marshal (buffer, p->scheme, &p->details); ++} ++ ++void ++grub_tpm2_mu_TPMS_RSA_PARMS_Marshal (grub_tpm2_buffer_t buffer, ++ TPMS_RSA_PARMS *p) ++{ ++ grub_tpm2_mu_TPMT_SYM_DEF_OBJECT_Marshal (buffer, &p->symmetric); ++ grub_tpm2_mu_TPMT_RSA_SCHEME_Marshal (buffer, &p->scheme); ++ grub_tpm2_buffer_pack_u16 (buffer, p->keyBits); ++ grub_tpm2_buffer_pack_u32 (buffer, p->exponent); ++} ++ ++void ++grub_tpm2_mu_TPMS_SYMCIPHER_PARMS_Marshal (grub_tpm2_buffer_t buffer, ++ TPMS_SYMCIPHER_PARMS *p) ++{ ++ grub_tpm2_mu_TPMT_SYM_DEF_OBJECT_Marshal (buffer, &p->sym); ++} ++ ++void ++grub_tpm2_mu_TPMT_ECC_SCHEME_Marshal (grub_tpm2_buffer_t buffer, ++ TPMT_ECC_SCHEME *p) ++{ ++ grub_tpm2_buffer_pack_u16 (buffer, p->scheme); ++ grub_tpm2_mu_TPMU_ASYM_SCHEME_Marshal (buffer, p->scheme, &p->details); ++} ++ ++void ++grub_tpm2_mu_TPMU_KDF_SCHEME_Marshal (grub_tpm2_buffer_t buffer, ++ TPMI_ALG_KDF scheme, ++ TPMU_KDF_SCHEME *p) ++{ ++ switch (scheme) ++ { ++ case TPM_ALG_MGF1: ++ grub_tpm2_buffer_pack_u16 (buffer, p->mgf1.hashAlg); ++ break; ++ case TPM_ALG_KDF1_SP800_56A: ++ grub_tpm2_buffer_pack_u16 (buffer, p->kdf1_sp800_56a.hashAlg); ++ break; ++ case TPM_ALG_KDF2: ++ grub_tpm2_buffer_pack_u16 (buffer, p->kdf2.hashAlg); ++ break; ++ case TPM_ALG_KDF1_SP800_108: ++ grub_tpm2_buffer_pack_u16 (buffer, p->kdf1_sp800_108.hashAlg); ++ break; ++ case TPM_ALG_NULL: ++ break; ++ default: ++ buffer->error = 1; ++ break; ++ } ++} ++ ++void ++grub_tpm2_mu_TPMT_KDF_SCHEME_Marshal (grub_tpm2_buffer_t buffer, ++ TPMT_KDF_SCHEME *p) ++{ ++ grub_tpm2_buffer_pack_u16 (buffer, p->scheme); ++ grub_tpm2_mu_TPMU_KDF_SCHEME_Marshal (buffer, p->scheme, &p->details); ++} ++ ++void ++grub_tpm2_mu_TPMS_ECC_PARMS_Marshal (grub_tpm2_buffer_t buffer, ++ TPMS_ECC_PARMS *p) ++{ ++ grub_tpm2_mu_TPMT_SYM_DEF_OBJECT_Marshal (buffer, &p->symmetric); ++ grub_tpm2_mu_TPMT_ECC_SCHEME_Marshal (buffer, &p->scheme); ++ grub_tpm2_buffer_pack_u16 (buffer, p->curveID); ++ grub_tpm2_mu_TPMT_KDF_SCHEME_Marshal (buffer, &p->kdf); ++} ++ ++void ++grub_tpm2_mu_TPMU_PUBLIC_PARMS_Marshal (grub_tpm2_buffer_t buffer, ++ grub_uint32_t type, ++ TPMU_PUBLIC_PARMS *p) ++{ ++ switch (type) ++ { ++ case TPM_ALG_KEYEDHASH: ++ grub_tpm2_mu_TPMS_KEYEDHASH_PARMS_Marshal (buffer, &p->keyedHashDetail); ++ break; ++ case TPM_ALG_SYMCIPHER: ++ grub_tpm2_mu_TPMS_SYMCIPHER_PARMS_Marshal (buffer, &p->symDetail); ++ break; ++ case TPM_ALG_RSA: ++ grub_tpm2_mu_TPMS_RSA_PARMS_Marshal (buffer, &p->rsaDetail); ++ break; ++ case TPM_ALG_ECC: ++ grub_tpm2_mu_TPMS_ECC_PARMS_Marshal (buffer, &p->eccDetail); ++ break; ++ default: ++ buffer->error = 1; ++ break; ++ } ++} ++ ++void ++grub_tpm2_mu_TPMS_ECC_POINT_Marshal (grub_tpm2_buffer_t buffer, ++ TPMS_ECC_POINT *p) ++{ ++ grub_tpm2_mu_TPM2B_Marshal (buffer, p->x.size, p->x.buffer); ++ grub_tpm2_mu_TPM2B_Marshal (buffer, p->y.size, p->y.buffer); ++} ++ ++void ++grub_tpm2_mu_TPMU_PUBLIC_ID_Marshal (grub_tpm2_buffer_t buffer, ++ TPMI_ALG_PUBLIC type, ++ TPMU_PUBLIC_ID *p) ++{ ++ switch(type) ++ { ++ case TPM_ALG_KEYEDHASH: ++ grub_tpm2_mu_TPM2B_Marshal (buffer, p->keyedHash.size, ++ p->keyedHash.buffer); ++ break; ++ case TPM_ALG_SYMCIPHER: ++ grub_tpm2_mu_TPM2B_Marshal (buffer, p->sym.size, p->sym.buffer); ++ break; ++ case TPM_ALG_RSA: ++ grub_tpm2_mu_TPM2B_Marshal (buffer, p->rsa.size, p->rsa.buffer); ++ break; ++ case TPM_ALG_ECC: ++ grub_tpm2_mu_TPMS_ECC_POINT_Marshal (buffer, &p->ecc); ++ break; ++ } ++} ++ ++void ++grub_tpm2_mu_TPMT_PUBLIC_Marshal (grub_tpm2_buffer_t buffer, ++ TPMT_PUBLIC *p) ++{ ++ grub_tpm2_buffer_pack_u16 (buffer, p->type); ++ grub_tpm2_buffer_pack_u16 (buffer, p->nameAlg); ++ grub_tpm2_mu_TPMA_OBJECT_Marshal (buffer, &p->objectAttributes); ++ grub_tpm2_mu_TPM2B_Marshal (buffer, p->authPolicy.size, p->authPolicy.buffer); ++ grub_tpm2_mu_TPMU_PUBLIC_PARMS_Marshal (buffer, p->type, &p->parameters); ++ grub_tpm2_mu_TPMU_PUBLIC_ID_Marshal (buffer, p->type, &p->unique); ++} ++ ++void ++grub_tpm2_mu_TPM2B_PUBLIC_Marshal (grub_tpm2_buffer_t buffer, ++ TPM2B_PUBLIC *p) ++{ ++ grub_uint32_t start; ++ grub_uint16_t size; ++ ++ if (p) ++ { ++ grub_tpm2_buffer_pack_u16 (buffer, p->size); ++ ++ start = buffer->size; ++ grub_tpm2_mu_TPMT_PUBLIC_Marshal (buffer, &p->publicArea); ++ size = grub_swap_bytes16 (buffer->size - start); ++ grub_memcpy (&buffer->data[start - sizeof (grub_uint16_t)], &size, ++ sizeof (size)); ++ } ++ else ++ grub_tpm2_buffer_pack_u16 (buffer, 0); ++} ++ ++void ++grub_tpm2_mu_TPMS_SENSITIVE_CREATE_Marshal (grub_tpm2_buffer_t buffer, ++ TPMS_SENSITIVE_CREATE *p) ++{ ++ grub_tpm2_mu_TPM2B_Marshal (buffer, p->userAuth.size, p->userAuth.buffer); ++ grub_tpm2_mu_TPM2B_Marshal (buffer, p->data.size, p->data.buffer); ++} ++ ++void ++grub_tpm2_mu_TPM2B_SENSITIVE_CREATE_Marshal (grub_tpm2_buffer_t buffer, ++ TPM2B_SENSITIVE_CREATE *sensitiveCreate) ++{ ++ grub_uint32_t start; ++ grub_uint16_t size; ++ ++ if (sensitiveCreate) ++ { ++ grub_tpm2_buffer_pack_u16 (buffer, sensitiveCreate->size); ++ start = buffer->size; ++ grub_tpm2_mu_TPMS_SENSITIVE_CREATE_Marshal (buffer, ++ &sensitiveCreate->sensitive); ++ size = grub_swap_bytes16 (buffer->size - start); ++ ++ grub_memcpy (&buffer->data[start - sizeof (grub_uint16_t)], &size, ++ sizeof (size)); ++ } ++ else ++ grub_tpm2_buffer_pack_u16 (buffer, 0); ++} ++ ++void ++grub_tpm2_mu_TPM2B_Unmarshal (grub_tpm2_buffer_t buffer, ++ TPM2B* p) ++{ ++ grub_tpm2_buffer_unpack_u16 (buffer, &p->size); ++ ++ for (grub_uint16_t i = 0; i < p->size; i++) ++ grub_tpm2_buffer_unpack_u8 (buffer, &p->buffer[i]); ++} ++ ++void ++grub_tpm2_mu_TPMS_AUTH_RESPONSE_Unmarshal (grub_tpm2_buffer_t buffer, ++ TPMS_AUTH_RESPONSE* p) ++{ ++ grub_uint8_t tmp; ++ grub_uint32_t tmp32; ++ ++ grub_tpm2_buffer_unpack_u16 (buffer, &p->nonce.size); ++ ++ if (p->nonce.size) ++ grub_tpm2_buffer_unpack (buffer, &p->nonce.buffer, p->nonce.size); ++ ++ grub_tpm2_buffer_unpack_u8 (buffer, &tmp); ++ tmp32 = tmp; ++ grub_memcpy (&p->sessionAttributes, &tmp32, sizeof (grub_uint32_t)); ++ ++ grub_tpm2_buffer_unpack_u16 (buffer, &p->hmac.size); ++ ++ if (p->hmac.size) ++ grub_tpm2_buffer_unpack (buffer, &p->hmac.buffer, p->hmac.size); ++} ++ ++void ++grub_tpm2_mu_TPM2B_DIGEST_Unmarshal (grub_tpm2_buffer_t buffer, ++ TPM2B_DIGEST* digest) ++{ ++ grub_tpm2_mu_TPM2B_Unmarshal (buffer, (TPM2B*)digest); ++} ++ ++void ++grub_tpm2_mu_TPMA_OBJECT_Unmarshal (grub_tpm2_buffer_t buffer, ++ TPMA_OBJECT *p) ++{ ++ grub_tpm2_buffer_unpack_u32 (buffer, (grub_uint32_t*)p); ++} ++ ++void ++grub_tpm2_mu_TPMS_SCHEME_HMAC_Unmarshal (grub_tpm2_buffer_t buffer, ++ TPMS_SCHEME_HMAC *p) ++{ ++ grub_tpm2_buffer_unpack_u16 (buffer, &p->hashAlg); ++} ++ ++void ++grub_tpm2_mu_TPMS_SCHEME_XOR_Unmarshal (grub_tpm2_buffer_t buffer, ++ TPMS_SCHEME_XOR *p) ++{ ++ grub_tpm2_buffer_unpack_u16 (buffer, &p->hashAlg); ++ grub_tpm2_buffer_unpack_u16 (buffer, &p->kdf); ++} ++ ++void ++grub_tpm2_mu_TPMU_SCHEME_KEYEDHASH_Unmarshal (grub_tpm2_buffer_t buffer, ++ TPMI_ALG_KEYEDHASH_SCHEME scheme, ++ TPMU_SCHEME_KEYEDHASH *p) ++{ ++ switch (scheme) ++ { ++ case TPM_ALG_HMAC: ++ grub_tpm2_mu_TPMS_SCHEME_HMAC_Unmarshal (buffer, &p->hmac); ++ break; ++ case TPM_ALG_XOR: ++ grub_tpm2_mu_TPMS_SCHEME_XOR_Unmarshal (buffer, &p->exclusiveOr); ++ break; ++ case TPM_ALG_NULL: ++ break; ++ default: ++ buffer->error = 1; ++ break; ++ } ++} ++ ++void ++grub_tpm2_mu_TPMT_KEYEDHASH_SCHEME_Unmarshal (grub_tpm2_buffer_t buffer, ++ TPMT_KEYEDHASH_SCHEME *p) ++{ ++ grub_tpm2_buffer_unpack_u16 (buffer, &p->scheme); ++ grub_tpm2_mu_TPMU_SCHEME_KEYEDHASH_Unmarshal (buffer, p->scheme, &p->details); ++} ++ ++void ++grub_tpm2_mu_TPMS_KEYEDHASH_PARMS_Unmarshal (grub_tpm2_buffer_t buffer, ++ TPMS_KEYEDHASH_PARMS *p) ++{ ++ grub_tpm2_mu_TPMT_KEYEDHASH_SCHEME_Unmarshal (buffer, &p->scheme); ++} ++ ++void ++grub_tpm2_mu_TPMU_SYM_KEY_BITS_Unmarshal (grub_tpm2_buffer_t buffer, ++ TPMI_ALG_SYM_OBJECT algorithm, ++ TPMU_SYM_KEY_BITS *p) ++{ ++ switch (algorithm) ++ { ++ case TPM_ALG_AES: ++ case TPM_ALG_SM4: ++ case TPM_ALG_CAMELLIA: ++ case TPM_ALG_XOR: ++ grub_tpm2_buffer_unpack_u16 (buffer, (grub_uint16_t*) p); ++ break; ++ case TPM_ALG_NULL: ++ break; ++ } ++} ++ ++void ++grub_tpm2_mu_TPMU_SYM_MODE_Unmarshal (grub_tpm2_buffer_t buffer, ++ TPMI_ALG_SYM_OBJECT algorithm, ++ TPMU_SYM_MODE *p) ++{ ++ switch (algorithm) ++ { ++ case TPM_ALG_AES: ++ case TPM_ALG_SM4: ++ case TPM_ALG_CAMELLIA: ++ grub_tpm2_buffer_unpack_u16 (buffer, (grub_uint16_t*) p); ++ break; ++ case TPM_ALG_XOR: ++ case TPM_ALG_NULL: ++ break; ++ } ++} ++ ++void ++grub_tpm2_mu_TPMT_SYM_DEF_OBJECT_Unmarshal (grub_tpm2_buffer_t buffer, ++ TPMT_SYM_DEF_OBJECT *p) ++{ ++ grub_tpm2_buffer_unpack_u16 (buffer, &p->algorithm); ++ grub_tpm2_mu_TPMU_SYM_KEY_BITS_Unmarshal (buffer, p->algorithm, &p->keyBits); ++ grub_tpm2_mu_TPMU_SYM_MODE_Unmarshal (buffer, p->algorithm, &p->mode); ++} ++ ++void ++grub_tpm2_mu_TPMS_SYMCIPHER_PARMS_Unmarshal (grub_tpm2_buffer_t buffer, ++ TPMS_SYMCIPHER_PARMS *p) ++{ ++ grub_tpm2_mu_TPMT_SYM_DEF_OBJECT_Unmarshal (buffer, &p->sym); ++} ++ ++void ++grub_tpm2_mu_TPMU_ASYM_SCHEME_Unmarshal (grub_tpm2_buffer_t buffer, ++ TPMI_ALG_RSA_DECRYPT scheme, ++ TPMU_ASYM_SCHEME *p __attribute__((unused))) ++{ ++ switch (scheme) ++ { ++ case TPM_ALG_NULL: ++ break; ++ default: ++ /* Unsupported */ ++ buffer->error = 1; ++ break; ++ } ++} ++ ++void ++grub_tpm2_mu_TPMT_RSA_SCHEME_Unmarshal (grub_tpm2_buffer_t buffer, ++ TPMT_RSA_SCHEME *p) ++{ ++ grub_tpm2_buffer_unpack_u16 (buffer, &p->scheme); ++ grub_tpm2_mu_TPMU_ASYM_SCHEME_Unmarshal (buffer, p->scheme, &p->details); ++} ++ ++void ++grub_tpm2_mu_TPMS_RSA_PARMS_Unmarshal (grub_tpm2_buffer_t buffer, ++ TPMS_RSA_PARMS *p) ++{ ++ grub_tpm2_mu_TPMT_SYM_DEF_OBJECT_Unmarshal (buffer, &p->symmetric); ++ grub_tpm2_mu_TPMT_RSA_SCHEME_Unmarshal (buffer, &p->scheme); ++ grub_tpm2_buffer_unpack_u16 (buffer, &p->keyBits); ++ grub_tpm2_buffer_unpack_u32 (buffer, &p->exponent); ++} ++ ++void ++grub_tpm2_mu_TPMT_ECC_SCHEME_Unmarshal (grub_tpm2_buffer_t buffer, ++ TPMT_ECC_SCHEME *p) ++{ ++ grub_tpm2_buffer_unpack_u16 (buffer, &p->scheme); ++ grub_tpm2_mu_TPMU_ASYM_SCHEME_Unmarshal (buffer, p->scheme, &p->details); ++} ++ ++void ++grub_tpm2_mu_TPMU_KDF_SCHEME_Unmarshal (grub_tpm2_buffer_t buffer, ++ TPMI_ALG_KDF scheme, ++ TPMU_KDF_SCHEME *p) ++{ ++ switch (scheme) ++ { ++ case TPM_ALG_MGF1: ++ grub_tpm2_buffer_unpack_u16 (buffer, &p->mgf1.hashAlg); ++ break; ++ case TPM_ALG_KDF1_SP800_56A: ++ grub_tpm2_buffer_unpack_u16 (buffer, &p->kdf1_sp800_56a.hashAlg); ++ break; ++ case TPM_ALG_KDF2: ++ grub_tpm2_buffer_unpack_u16 (buffer, &p->kdf2.hashAlg); ++ break; ++ case TPM_ALG_KDF1_SP800_108: ++ grub_tpm2_buffer_unpack_u16 (buffer, &p->kdf1_sp800_108.hashAlg); ++ break; ++ case TPM_ALG_NULL: ++ break; ++ default: ++ buffer->error = 1; ++ break; ++ } ++} ++ ++void ++grub_tpm2_mu_TPMT_KDF_SCHEME_Unmarshal (grub_tpm2_buffer_t buffer, ++ TPMT_KDF_SCHEME *p) ++{ ++ grub_tpm2_buffer_unpack_u16 (buffer, &p->scheme); ++ grub_tpm2_mu_TPMU_KDF_SCHEME_Unmarshal (buffer, p->scheme, &p->details); ++} ++ ++void ++grub_tpm2_mu_TPMS_ECC_PARMS_Unmarshal (grub_tpm2_buffer_t buffer, ++ TPMS_ECC_PARMS *p) ++{ ++ grub_tpm2_mu_TPMT_SYM_DEF_OBJECT_Unmarshal (buffer, &p->symmetric); ++ grub_tpm2_mu_TPMT_ECC_SCHEME_Unmarshal (buffer, &p->scheme ); ++ grub_tpm2_buffer_unpack_u16 (buffer, &p->curveID); ++ grub_tpm2_mu_TPMT_KDF_SCHEME_Unmarshal (buffer, &p->kdf); ++} ++ ++void ++grub_tpm2_mu_TPMU_PUBLIC_PARMS_Unmarshal (grub_tpm2_buffer_t buffer, ++ grub_uint32_t type, ++ TPMU_PUBLIC_PARMS *p) ++{ ++ switch (type) ++ { ++ case TPM_ALG_KEYEDHASH: ++ grub_tpm2_mu_TPMS_KEYEDHASH_PARMS_Unmarshal (buffer, &p->keyedHashDetail); ++ break; ++ case TPM_ALG_SYMCIPHER: ++ grub_tpm2_mu_TPMS_SYMCIPHER_PARMS_Unmarshal (buffer, &p->symDetail); ++ break; ++ case TPM_ALG_RSA: ++ grub_tpm2_mu_TPMS_RSA_PARMS_Unmarshal (buffer, &p->rsaDetail); ++ break; ++ case TPM_ALG_ECC: ++ grub_tpm2_mu_TPMS_ECC_PARMS_Unmarshal (buffer, &p->eccDetail); ++ break; ++ default: ++ buffer->error = 1; ++ break; ++ } ++} ++ ++void ++grub_tpm2_mu_TPMS_ECC_POINT_Unmarshal (grub_tpm2_buffer_t buffer, ++ TPMS_ECC_POINT *p) ++{ ++ grub_tpm2_mu_TPM2B_Unmarshal (buffer, (TPM2B*) &p->x); ++ grub_tpm2_mu_TPM2B_Unmarshal (buffer, (TPM2B*) &p->y); ++} ++ ++void ++grub_tpm2_mu_TPMU_PUBLIC_ID_Unmarshal (grub_tpm2_buffer_t buffer, ++ TPMI_ALG_PUBLIC type, ++ TPMU_PUBLIC_ID *p) ++{ ++ switch(type) ++ { ++ case TPM_ALG_KEYEDHASH: ++ grub_tpm2_mu_TPM2B_Unmarshal (buffer, (TPM2B*) &p->keyedHash); ++ break; ++ case TPM_ALG_SYMCIPHER: ++ grub_tpm2_mu_TPM2B_Unmarshal (buffer, (TPM2B*) &p->sym); ++ break; ++ case TPM_ALG_RSA: ++ grub_tpm2_mu_TPM2B_Unmarshal (buffer, (TPM2B*) &p->rsa); ++ break; ++ case TPM_ALG_ECC: ++ grub_tpm2_mu_TPMS_ECC_POINT_Unmarshal (buffer, &p->ecc); ++ break; ++ } ++} ++ ++void ++grub_tpm2_mu_TPMT_PUBLIC_Unmarshal (grub_tpm2_buffer_t buffer, ++ TPMT_PUBLIC *p) ++{ ++ grub_tpm2_buffer_unpack_u16 (buffer, &p->type); ++ grub_tpm2_buffer_unpack_u16 (buffer, &p->nameAlg); ++ grub_tpm2_mu_TPMA_OBJECT_Unmarshal (buffer, &p->objectAttributes); ++ grub_tpm2_mu_TPM2B_Unmarshal (buffer, (TPM2B*) &p->authPolicy); ++ grub_tpm2_mu_TPMU_PUBLIC_PARMS_Unmarshal (buffer, p->type, &p->parameters); ++ grub_tpm2_mu_TPMU_PUBLIC_ID_Unmarshal (buffer, p->type, &p->unique); ++} ++ ++void ++grub_tpm2_mu_TPM2B_PUBLIC_Unmarshal (grub_tpm2_buffer_t buffer, ++ TPM2B_PUBLIC *p) ++{ ++ grub_tpm2_buffer_unpack_u16 (buffer, &p->size); ++ grub_tpm2_mu_TPMT_PUBLIC_Unmarshal (buffer, &p->publicArea); ++} ++ ++void ++grub_tpm2_mu_TPMS_NV_PUBLIC_Unmarshal (grub_tpm2_buffer_t buffer, ++ TPMS_NV_PUBLIC *p) ++{ ++ grub_tpm2_buffer_unpack_u32 (buffer, &p->nvIndex); ++ grub_tpm2_buffer_unpack_u16 (buffer, &p->nameAlg); ++ grub_tpm2_buffer_unpack_u32 (buffer, &p->attributes); ++ grub_tpm2_mu_TPM2B_DIGEST_Unmarshal (buffer, &p->authPolicy); ++ grub_tpm2_buffer_unpack_u16 (buffer, &p->dataSize); ++} ++ ++void ++grub_tpm2_mu_TPM2B_NV_PUBLIC_Unmarshal (grub_tpm2_buffer_t buffer, ++ TPM2B_NV_PUBLIC *p) ++{ ++ grub_tpm2_buffer_unpack_u16 (buffer, &p->size); ++ grub_tpm2_mu_TPMS_NV_PUBLIC_Unmarshal (buffer, &p->nvPublic); ++} ++ ++void ++grub_tpm2_mu_TPM2B_NAME_Unmarshal (grub_tpm2_buffer_t buffer, ++ TPM2B_NAME *n) ++{ ++ grub_tpm2_buffer_unpack_u16 (buffer, &n->size); ++ grub_tpm2_buffer_unpack (buffer, n->name, n->size); ++} ++ ++void ++grub_tpm2_mu_TPMS_TAGGED_PROPERTY_Unmarshal (grub_tpm2_buffer_t buffer, ++ TPMS_TAGGED_PROPERTY* property) ++{ ++ grub_tpm2_buffer_unpack_u32 (buffer, &property->property); ++ grub_tpm2_buffer_unpack_u32 (buffer, &property->value); ++} ++ ++void ++grub_tpm2_mu_TPMS_CAPABILITY_DATA_tpmProperties_Unmarshal (grub_tpm2_buffer_t buffer, ++ TPMS_CAPABILITY_DATA* capabilityData) ++{ ++ grub_tpm2_buffer_unpack_u32 (buffer, ++ &capabilityData->data.tpmProperties.count); ++ ++ if (buffer->error) ++ return; ++ ++ for (grub_uint32_t i = 0; i < capabilityData->data.tpmProperties.count; i++) ++ grub_tpm2_mu_TPMS_TAGGED_PROPERTY_Unmarshal (buffer, ++ &capabilityData->data.tpmProperties.tpmProperty[i]); ++} ++ ++void ++grub_tpm2_mu_TPMT_TK_CREATION_Unmarshal (grub_tpm2_buffer_t buffer, ++ TPMT_TK_CREATION *p) ++{ ++ grub_tpm2_buffer_unpack_u16 (buffer, &p->tag); ++ grub_tpm2_buffer_unpack_u32 (buffer, &p->hierarchy); ++ grub_tpm2_mu_TPM2B_Unmarshal (buffer, (TPM2B*) &p->digest); ++} ++ ++void ++grub_tpm2_mu_TPMS_PCR_SELECTION_Unmarshal (grub_tpm2_buffer_t buf, ++ TPMS_PCR_SELECTION* pcrSelection) ++{ ++ grub_tpm2_buffer_unpack_u16 (buf, &pcrSelection->hash); ++ grub_tpm2_buffer_unpack_u8 (buf, &pcrSelection->sizeOfSelect); ++ ++ for (grub_uint32_t i = 0; i < pcrSelection->sizeOfSelect; i++) ++ grub_tpm2_buffer_unpack_u8 (buf, &pcrSelection->pcrSelect[i]); ++} ++ ++void ++grub_tpm2_mu_TPML_PCR_SELECTION_Unmarshal (grub_tpm2_buffer_t buf, ++ TPML_PCR_SELECTION* pcrSelection) ++{ ++ grub_tpm2_buffer_unpack_u32 (buf, &pcrSelection->count); ++ ++ for (grub_uint32_t i = 0; i < pcrSelection->count; i++) ++ grub_tpm2_mu_TPMS_PCR_SELECTION_Unmarshal (buf, &pcrSelection->pcrSelections[i]); ++} ++ ++void ++grub_tpm2_mu_TPML_DIGEST_Unmarshal (grub_tpm2_buffer_t buf, ++ TPML_DIGEST* digest) ++{ ++ grub_tpm2_buffer_unpack_u32 (buf, &digest->count); ++ ++ for (grub_uint32_t i = 0; i < digest->count; i++) ++ grub_tpm2_mu_TPM2B_DIGEST_Unmarshal (buf, &digest->digests[i]); ++} +diff --git a/grub-core/tpm2/tcg2.c b/grub-core/tpm2/tcg2.c +new file mode 100644 +index 0000000000..44837218a2 +--- /dev/null ++++ b/grub-core/tpm2/tcg2.c +@@ -0,0 +1,143 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2022 Microsoft Corporation ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++static grub_err_t ++grub_tcg2_get_caps (grub_efi_tpm2_protocol_t *protocol, int *tpm2, ++ grub_size_t *max_output_size) ++{ ++ grub_efi_status_t status; ++ ++ static int has_caps = 0; ++ static EFI_TCG2_BOOT_SERVICE_CAPABILITY caps = ++ { ++ .Size = (grub_uint8_t) sizeof (caps) ++ }; ++ ++ if (has_caps) ++ goto exit; ++ ++ status = efi_call_2 (protocol->get_capability, protocol, &caps); ++ if (status != GRUB_EFI_SUCCESS || !caps.TPMPresentFlag) ++ return GRUB_ERR_FILE_NOT_FOUND; ++ ++ has_caps = 1; ++ ++exit: ++ if (tpm2) ++ *tpm2 = caps.TPMPresentFlag; ++ if (max_output_size) ++ *max_output_size = caps.MaxResponseSize; ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_tcg2_get_protocol (grub_efi_tpm2_protocol_t **protocol) ++{ ++ static grub_efi_guid_t tpm2_guid = EFI_TPM2_GUID; ++ static grub_efi_tpm2_protocol_t *tpm2_protocol = NULL; ++ ++ int tpm2; ++ grub_efi_handle_t *handles; ++ grub_efi_uintn_t num_handles; ++ grub_efi_handle_t tpm2_handle; ++ grub_err_t err = GRUB_ERR_FILE_NOT_FOUND; ++ ++ if (tpm2_protocol) ++ { ++ *protocol = tpm2_protocol; ++ return GRUB_ERR_NONE; ++ } ++ ++ handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL, &tpm2_guid, NULL, ++ &num_handles); ++ if (!handles || !num_handles) ++ return err; ++ ++ tpm2_handle = handles[0]; ++ ++ tpm2_protocol = grub_efi_open_protocol (tpm2_handle, &tpm2_guid, ++ GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); ++ if (!tpm2_protocol) ++ goto exit; ++ ++ err = grub_tcg2_get_caps (tpm2_protocol, &tpm2, NULL); ++ if (err || !tpm2) ++ goto exit; ++ ++ *protocol = tpm2_protocol; ++ err = GRUB_ERR_NONE; ++ ++exit: ++ grub_free (handles); ++ return err; ++} ++ ++grub_err_t ++grub_tcg2_get_max_output_size (grub_size_t *size) ++{ ++ grub_err_t err; ++ grub_size_t max; ++ grub_efi_tpm2_protocol_t *protocol; ++ ++ if (!size) ++ return GRUB_ERR_BAD_ARGUMENT; ++ ++ err = grub_tcg2_get_protocol (&protocol); ++ if (err) ++ return err; ++ ++ err = grub_tcg2_get_caps (protocol, NULL, &max); ++ if (err) ++ return err; ++ ++ *size = max; ++ ++ return GRUB_ERR_NONE; ++} ++ ++grub_err_t ++grub_tcg2_submit_command (grub_size_t input_size, ++ grub_uint8_t *input, ++ grub_size_t output_size, ++ grub_uint8_t *output) ++{ ++ grub_err_t err; ++ grub_efi_status_t status; ++ grub_efi_tpm2_protocol_t *protocol; ++ ++ if (!input_size || !input || !output_size || !output) ++ return GRUB_ERR_BAD_ARGUMENT; ++ ++ err = grub_tcg2_get_protocol (&protocol); ++ if (err) ++ return err; ++ ++ status = efi_call_5 (protocol->submit_command, protocol, input_size, input, ++ output_size, output); ++ if (status != GRUB_EFI_SUCCESS) ++ return GRUB_ERR_INVALID_COMMAND; ++ ++ return GRUB_ERR_NONE; ++} +diff --git a/grub-core/tpm2/tpm2.c b/grub-core/tpm2/tpm2.c +new file mode 100644 +index 0000000000..2407a844d2 +--- /dev/null ++++ b/grub-core/tpm2/tpm2.c +@@ -0,0 +1,711 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2022 Microsoft Corporation ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static TPM_RC ++grub_tpm2_submit_command (TPMI_ST_COMMAND_TAG tag, ++ TPM_CC commandCode, ++ TPM_RC* responseCode, ++ const struct grub_tpm2_buffer* in, ++ struct grub_tpm2_buffer* out) ++{ ++ grub_err_t err; ++ struct grub_tpm2_buffer buf; ++ TPMI_ST_COMMAND_TAG tag_out; ++ grub_uint32_t command_size; ++ grub_size_t max_output_size; ++ ++ /* Marshal */ ++ grub_tpm2_buffer_init (&buf); ++ grub_tpm2_buffer_pack_u16 (&buf, tag); ++ grub_tpm2_buffer_pack_u32 (&buf, 0); ++ grub_tpm2_buffer_pack_u32 (&buf, commandCode); ++ grub_tpm2_buffer_pack (&buf, in->data, in->size); ++ ++ if (buf.error) ++ return TPM_RC_FAILURE; ++ ++ command_size = grub_swap_bytes32 (buf.size); ++ grub_memcpy (&buf.data[sizeof (grub_uint16_t)], &command_size, ++ sizeof (command_size)); ++ ++ /* Stay within output block limits */ ++ err = grub_tcg2_get_max_output_size (&max_output_size); ++ if (err || max_output_size > out->cap) ++ max_output_size = out->cap - 1; ++ ++ /* Submit */ ++ err = grub_tcg2_submit_command (buf.size, buf.data, max_output_size, ++ out->data); ++ if (err) ++ return TPM_RC_FAILURE; ++ ++ /* Unmarshal*/ ++ out->size = sizeof (grub_uint16_t) + sizeof (grub_uint32_t) + ++ sizeof (grub_uint32_t); ++ grub_tpm2_buffer_unpack_u16 (out, &tag_out); ++ grub_tpm2_buffer_unpack_u32 (out, &command_size); ++ grub_tpm2_buffer_unpack_u32 (out, responseCode); ++ out->size = command_size; ++ if (out->error) ++ return TPM_RC_FAILURE; ++ ++ return TPM_RC_SUCCESS; ++} ++ ++TPM_RC ++TPM2_CreatePrimary (TPMI_RH_HIERARCHY primaryHandle, ++ const TPMS_AUTH_COMMAND *authCommand, ++ TPM2B_SENSITIVE_CREATE *inSensitive, ++ TPM2B_PUBLIC *inPublic, ++ TPM2B_DATA *outsideInfo, ++ TPML_PCR_SELECTION *creationPCR, ++ TPM_HANDLE *objectHandle, ++ TPM2B_PUBLIC *outPublic, ++ TPM2B_CREATION_DATA *creationData, ++ TPM2B_DIGEST *creationHash, ++ TPMT_TK_CREATION *creationTicket, ++ TPM2B_NAME *name, ++ TPMS_AUTH_RESPONSE *authResponse) ++{ ++ TPM_RC rc; ++ struct grub_tpm2_buffer in; ++ struct grub_tpm2_buffer out; ++ TPM_HANDLE objectHandleTmp; ++ TPM2B_PUBLIC outPublicTmp; ++ TPM2B_CREATION_DATA creationDataTmp; ++ TPM2B_DIGEST creationHashTmp; ++ TPMT_TK_CREATION creationTicketTmp; ++ TPM2B_NAME nameTmp; ++ TPMS_AUTH_RESPONSE authResponseTmp; ++ TPMI_ST_COMMAND_TAG tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS; ++ TPM_RC responseCode; ++ grub_uint32_t parameterSize; ++ ++ if (!objectHandle) ++ objectHandle = &objectHandleTmp; ++ if (!outPublic) ++ outPublic = &outPublicTmp; ++ if (!creationData) ++ creationData = &creationDataTmp; ++ if (!creationHash) ++ creationHash = &creationHashTmp; ++ if (!creationTicket) ++ creationTicket = &creationTicketTmp; ++ if (!name) ++ name = &nameTmp; ++ if (!authResponse) ++ authResponse = &authResponseTmp; ++ ++ grub_memset (outPublic, 0, sizeof (*outPublic)); ++ grub_memset (creationData, 0, sizeof (*creationData)); ++ grub_memset (creationHash, 0, sizeof (*creationHash)); ++ grub_memset (creationTicket, 0, sizeof (*creationTicket)); ++ grub_memset (name, 0, sizeof (*name)); ++ grub_memset (authResponse, 0, sizeof (*authResponse)); ++ ++ /* Marshal */ ++ grub_tpm2_buffer_init (&in); ++ grub_tpm2_buffer_pack_u32 (&in, primaryHandle); ++ if (authCommand) ++ grub_tpm2_mu_TPMS_AUTH_COMMAND_Marshal (&in, authCommand); ++ grub_tpm2_mu_TPM2B_SENSITIVE_CREATE_Marshal (&in, inSensitive); ++ grub_tpm2_mu_TPM2B_PUBLIC_Marshal (&in, inPublic); ++ grub_tpm2_mu_TPM2B_Marshal (&in, outsideInfo->size, outsideInfo->buffer); ++ grub_tpm2_mu_TPML_PCR_SELECTION_Marshal (&in, creationPCR); ++ if (in.error) ++ return TPM_RC_FAILURE; ++ ++ /* Submit */ ++ grub_tpm2_buffer_init (&out); ++ rc = grub_tpm2_submit_command (tag, TPM_CC_CreatePrimary, &responseCode, &in, ++ &out); ++ if (rc != TPM_RC_SUCCESS) ++ return rc; ++ if (responseCode != TPM_RC_SUCCESS) ++ return responseCode; ++ ++ /* Unmarshal*/ ++ grub_tpm2_buffer_unpack_u32 (&out, objectHandle); ++ if (tag == TPM_ST_SESSIONS) ++ grub_tpm2_buffer_unpack_u32 (&out, ¶meterSize); ++ grub_tpm2_mu_TPM2B_PUBLIC_Unmarshal (&out, outPublic); ++ grub_tpm2_mu_TPM2B_Unmarshal (&out, (TPM2B*)creationData); ++ grub_tpm2_mu_TPM2B_Unmarshal (&out, (TPM2B*)creationHash); ++ grub_tpm2_mu_TPMT_TK_CREATION_Unmarshal (&out, creationTicket); ++ grub_tpm2_mu_TPM2B_Unmarshal (&out, (TPM2B*)name); ++ if (tag == TPM_ST_SESSIONS) ++ grub_tpm2_mu_TPMS_AUTH_RESPONSE_Unmarshal (&out, authResponse); ++ if (out.error) ++ return TPM_RC_FAILURE; ++ ++ return TPM_RC_SUCCESS; ++} ++ ++TPM_RC ++TPM2_StartAuthSession (TPMI_DH_OBJECT tpmKey, ++ TPMI_DH_ENTITY bind, ++ const TPMS_AUTH_COMMAND *authCommand, ++ TPM2B_NONCE *nonceCaller, ++ TPM2B_ENCRYPTED_SECRET *encryptedSalt, ++ TPM_SE sessionType, ++ TPMT_SYM_DEF *symmetric, ++ TPMI_ALG_HASH authHash, ++ TPMI_SH_AUTH_SESSION *sessionHandle, ++ TPM2B_NONCE *nonceTpm, ++ TPMS_AUTH_RESPONSE *authResponse) ++{ ++ TPM_RC rc; ++ struct grub_tpm2_buffer in; ++ struct grub_tpm2_buffer out; ++ TPMI_SH_AUTH_SESSION sessionHandleTmp; ++ TPM2B_NONCE nonceTpmTmp; ++ TPMS_AUTH_RESPONSE authResponseTmp; ++ TPMI_ST_COMMAND_TAG tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS; ++ TPM_RC responseCode; ++ grub_uint32_t param_size; ++ ++ if (!sessionHandle) ++ sessionHandle = &sessionHandleTmp; ++ if (!nonceTpm) ++ nonceTpm = &nonceTpmTmp; ++ if (!authResponse) ++ authResponse = &authResponseTmp; ++ ++ grub_memset (sessionHandle, 0, sizeof (*sessionHandle)); ++ grub_memset (nonceTpm, 0, sizeof (*nonceTpm)); ++ grub_memset (authResponse, 0, sizeof (*authResponse)); ++ ++ /* Marshal */ ++ grub_tpm2_buffer_init (&in); ++ grub_tpm2_buffer_pack_u32 (&in, tpmKey); ++ grub_tpm2_buffer_pack_u32 (&in, bind); ++ if (tag == TPM_ST_SESSIONS) ++ grub_tpm2_mu_TPMS_AUTH_COMMAND_Marshal (&in, authCommand); ++ grub_tpm2_mu_TPM2B_Marshal (&in, nonceCaller->size, nonceCaller->buffer); ++ grub_tpm2_mu_TPM2B_Marshal (&in, encryptedSalt->size, encryptedSalt->secret); ++ grub_tpm2_buffer_pack_u8 (&in, sessionType); ++ grub_tpm2_mu_TPMT_SYM_DEF_Marshal (&in, symmetric); ++ grub_tpm2_buffer_pack_u16 (&in, authHash); ++ if (in.error) ++ return TPM_RC_FAILURE; ++ ++ /* Submit */ ++ grub_tpm2_buffer_init (&out); ++ rc = grub_tpm2_submit_command (tag, TPM_CC_StartAuthSession, &responseCode, ++ &in, &out); ++ if (rc != TPM_RC_SUCCESS) ++ return rc; ++ if (responseCode != TPM_RC_SUCCESS) ++ return responseCode; ++ ++ /* Unmarshal*/ ++ grub_tpm2_buffer_unpack_u32 (&out, sessionHandle); ++ if (tag == TPM_ST_SESSIONS) ++ grub_tpm2_buffer_unpack_u32 (&out, ¶m_size); ++ grub_tpm2_mu_TPM2B_Unmarshal (&out, (TPM2B*)nonceTpm); ++ if (tag == TPM_ST_SESSIONS) ++ grub_tpm2_mu_TPMS_AUTH_RESPONSE_Unmarshal (&out, authResponse); ++ if (out.error) ++ return TPM_RC_FAILURE; ++ ++ return TPM_RC_SUCCESS; ++} ++ ++TPM_RC ++TPM2_PolicyPCR (TPMI_SH_POLICY policySessions, ++ const TPMS_AUTH_COMMAND *authCommand, ++ TPM2B_DIGEST *pcrDigest, ++ TPML_PCR_SELECTION *pcrs, ++ TPMS_AUTH_RESPONSE *authResponse) ++{ ++ TPM_RC rc; ++ struct grub_tpm2_buffer in; ++ struct grub_tpm2_buffer out; ++ TPMS_AUTH_RESPONSE authResponseTmp; ++ TPMI_ST_COMMAND_TAG tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS; ++ TPM_RC responseCode; ++ grub_uint32_t param_size; ++ ++ if (!authResponse) ++ authResponse = &authResponseTmp; ++ ++ grub_memset (authResponse, 0, sizeof (*authResponse)); ++ ++ /* Marshal */ ++ grub_tpm2_buffer_init (&in); ++ grub_tpm2_buffer_pack_u32 (&in, policySessions); ++ if (tag == TPM_ST_SESSIONS) ++ grub_tpm2_mu_TPMS_AUTH_COMMAND_Marshal (&in, authCommand); ++ grub_tpm2_mu_TPM2B_Marshal (&in, pcrDigest->size, pcrDigest->buffer); ++ grub_tpm2_mu_TPML_PCR_SELECTION_Marshal (&in, pcrs); ++ if (in.error) ++ return TPM_RC_FAILURE; ++ ++ /* Submit */ ++ grub_tpm2_buffer_init (&out); ++ rc = grub_tpm2_submit_command (tag, TPM_CC_PolicyPCR, &responseCode, &in, ++ &out); ++ if (rc != TPM_RC_SUCCESS) ++ return rc; ++ if (responseCode != TPM_RC_SUCCESS) ++ return responseCode; ++ ++ /* Unmarshal*/ ++ if (tag == TPM_ST_SESSIONS) ++ grub_tpm2_buffer_unpack_u32 (&out, ¶m_size); ++ if (tag == TPM_ST_SESSIONS) ++ grub_tpm2_mu_TPMS_AUTH_RESPONSE_Unmarshal (&out, authResponse); ++ if (out.error) ++ return TPM_RC_FAILURE; ++ ++ return TPM_RC_SUCCESS; ++} ++ ++TPM_RC ++TPM2_ReadPublic (TPMI_DH_OBJECT objectHandle, ++ const TPMS_AUTH_COMMAND* authCommand, ++ TPM2B_PUBLIC *outPublic) ++{ ++ TPM_RC rc; ++ struct grub_tpm2_buffer in; ++ struct grub_tpm2_buffer out; ++ TPMI_ST_COMMAND_TAG tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS; ++ TPM_RC responseCode; ++ grub_uint32_t parameterSize; ++ ++ /* Marshal */ ++ grub_tpm2_buffer_init (&in); ++ grub_tpm2_buffer_pack_u32 (&in, objectHandle); ++ if (in.error) ++ return TPM_RC_FAILURE; ++ ++ /* Submit */ ++ grub_tpm2_buffer_init (&out); ++ rc = grub_tpm2_submit_command (tag, TPM_CC_ReadPublic, &responseCode, &in, ++ &out); ++ if (rc != TPM_RC_SUCCESS) ++ return rc; ++ if (responseCode != TPM_RC_SUCCESS) ++ return responseCode; ++ ++ /* Unmarshal*/ ++ if (tag == TPM_ST_SESSIONS) ++ grub_tpm2_buffer_unpack_u32 (&out, ¶meterSize); ++ grub_tpm2_mu_TPM2B_PUBLIC_Unmarshal (&out, outPublic); ++ if (out.error) ++ return TPM_RC_FAILURE; ++ ++ return TPM_RC_SUCCESS; ++} ++ ++TPM_RC ++TPM2_Load (TPMI_DH_OBJECT parent_handle, ++ TPMS_AUTH_COMMAND const *authCommand, ++ TPM2B_PRIVATE *inPrivate, ++ TPM2B_PUBLIC *inPublic, ++ TPM_HANDLE *objectHandle, ++ TPM2B_NAME *name, ++ TPMS_AUTH_RESPONSE *authResponse) ++{ ++ TPM_RC rc; ++ struct grub_tpm2_buffer in; ++ struct grub_tpm2_buffer out; ++ TPM_HANDLE objectHandleTmp; ++ TPM2B_NAME nonceTmp; ++ TPMS_AUTH_RESPONSE authResponseTmp; ++ TPMI_ST_COMMAND_TAG tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS; ++ TPM_RC responseCode; ++ grub_uint32_t param_size; ++ ++ if (!objectHandle) ++ objectHandle = &objectHandleTmp; ++ if (!name) ++ name = &nonceTmp; ++ if (!authResponse) ++ authResponse = &authResponseTmp; ++ ++ grub_memset (objectHandle, 0, sizeof (*objectHandle)); ++ grub_memset (name, 0, sizeof (*name)); ++ grub_memset (authResponse, 0, sizeof (*authResponse)); ++ ++ /* Marshal */ ++ grub_tpm2_buffer_init (&in); ++ grub_tpm2_buffer_pack_u32 (&in, parent_handle); ++ if (authCommand) ++ grub_tpm2_mu_TPMS_AUTH_COMMAND_Marshal (&in, authCommand); ++ grub_tpm2_mu_TPM2B_Marshal (&in, inPrivate->size, inPrivate->buffer); ++ grub_tpm2_mu_TPM2B_PUBLIC_Marshal (&in, inPublic); ++ if (in.error) ++ return TPM_RC_FAILURE; ++ ++ /* Submit */ ++ grub_tpm2_buffer_init (&out); ++ rc = grub_tpm2_submit_command (tag, TPM_CC_Load, &responseCode, &in, &out); ++ if (rc != TPM_RC_SUCCESS) ++ return rc; ++ if (responseCode != TPM_RC_SUCCESS) ++ return responseCode; ++ ++ /* Unmarshal*/ ++ grub_tpm2_buffer_unpack_u32 (&out, objectHandle); ++ if (tag == TPM_ST_SESSIONS) ++ grub_tpm2_buffer_unpack_u32 (&out, ¶m_size); ++ grub_tpm2_mu_TPM2B_Unmarshal (&out, (TPM2B*)name); ++ if (tag == TPM_ST_SESSIONS) ++ grub_tpm2_mu_TPMS_AUTH_RESPONSE_Unmarshal (&out, authResponse); ++ if (out.error) ++ return TPM_RC_FAILURE; ++ ++ return TPM_RC_SUCCESS; ++} ++ ++TPM_RC ++TPM2_Unseal (TPMI_DH_OBJECT itemHandle, ++ const TPMS_AUTH_COMMAND *authCommand, ++ TPM2B_SENSITIVE_DATA *outData, ++ TPMS_AUTH_RESPONSE *authResponse) ++{ ++ TPM_RC rc; ++ struct grub_tpm2_buffer in; ++ struct grub_tpm2_buffer out; ++ TPM2B_SENSITIVE_DATA outDataTmp; ++ TPMS_AUTH_RESPONSE authResponseTmp; ++ TPMI_ST_COMMAND_TAG tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS; ++ TPM_RC responseCode; ++ grub_uint32_t param_size; ++ ++ if (!outData) ++ outData = &outDataTmp; ++ if (!authResponse) ++ authResponse = &authResponseTmp; ++ ++ grub_memset (outData, 0, sizeof (*outData)); ++ grub_memset (authResponse, 0, sizeof (*authResponse)); ++ ++ /* Marshal */ ++ grub_tpm2_buffer_init (&in); ++ grub_tpm2_buffer_pack_u32 (&in, itemHandle); ++ if (authCommand) ++ grub_tpm2_mu_TPMS_AUTH_COMMAND_Marshal (&in, authCommand); ++ if (in.error) ++ return TPM_RC_FAILURE; ++ ++ /* Submit */ ++ grub_tpm2_buffer_init (&out); ++ rc = grub_tpm2_submit_command (tag, TPM_CC_Unseal, &responseCode, &in, &out); ++ if (rc != TPM_RC_SUCCESS) ++ return rc; ++ if (responseCode != TPM_RC_SUCCESS) ++ return responseCode; ++ ++ // Unmarhsal ++ if (tag == TPM_ST_SESSIONS) ++ grub_tpm2_buffer_unpack_u32 (&out, ¶m_size); ++ grub_tpm2_mu_TPM2B_Unmarshal (&out, (TPM2B*)outData); ++ if (tag == TPM_ST_SESSIONS) ++ grub_tpm2_mu_TPMS_AUTH_RESPONSE_Unmarshal (&out, authResponse); ++ if (out.error) ++ return TPM_RC_FAILURE; ++ ++ return TPM_RC_SUCCESS; ++} ++ ++TPM_RC ++TPM2_FlushContext (TPMI_DH_CONTEXT handle) ++{ ++ TPM_RC rc; ++ struct grub_tpm2_buffer in; ++ struct grub_tpm2_buffer out; ++ TPM_RC responseCode; ++ ++ /* Marshal */ ++ grub_tpm2_buffer_init (&in); ++ grub_tpm2_buffer_pack_u32 (&in, handle); ++ if (in.error) ++ return TPM_RC_FAILURE; ++ ++ /* Submit */ ++ grub_tpm2_buffer_init (&out); ++ rc = grub_tpm2_submit_command (TPM_ST_NO_SESSIONS, TPM_CC_FlushContext, ++ &responseCode, &in, &out); ++ if (rc != TPM_RC_SUCCESS) ++ return rc; ++ if (responseCode != TPM_RC_SUCCESS) ++ return responseCode; ++ ++ /* Unmarshal*/ ++ if (out.error) ++ return TPM_RC_FAILURE; ++ ++ return TPM_RC_SUCCESS; ++} ++ ++TPM_RC ++TPM2_PCR_Read (const TPMS_AUTH_COMMAND *authCommand, ++ TPML_PCR_SELECTION *pcrSelectionIn, ++ grub_uint32_t *pcrUpdateCounter, ++ TPML_PCR_SELECTION *pcrSelectionOut, ++ TPML_DIGEST *pcrValues, ++ TPMS_AUTH_RESPONSE *authResponse) ++{ ++ TPM_RC rc; ++ struct grub_tpm2_buffer in; ++ struct grub_tpm2_buffer out; ++ grub_uint32_t pcrUpdateCounterTmp; ++ TPML_PCR_SELECTION pcrSelectionOutTmp; ++ TPML_DIGEST pcrValuesTmp; ++ TPMS_AUTH_RESPONSE authResponseTmp; ++ TPMI_ST_COMMAND_TAG tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS; ++ TPM_RC responseCode; ++ grub_uint32_t parameterSize; ++ ++ if (!pcrSelectionIn) ++ return TPM_RC_FAILURE; ++ ++ if (!pcrUpdateCounter) ++ pcrUpdateCounter = &pcrUpdateCounterTmp; ++ if (!pcrSelectionOut) ++ pcrSelectionOut = &pcrSelectionOutTmp; ++ if (!pcrValues) ++ pcrValues = &pcrValuesTmp; ++ if (!authResponse) ++ authResponse = &authResponseTmp; ++ ++ /* Marshal */ ++ grub_tpm2_buffer_init (&in); ++ grub_tpm2_mu_TPML_PCR_SELECTION_Marshal (&in, pcrSelectionIn); ++ if (in.error) ++ return TPM_RC_FAILURE; ++ ++ /* Submit */ ++ grub_tpm2_buffer_init (&out); ++ rc = grub_tpm2_submit_command (tag, TPM_CC_PCR_Read, &responseCode, &in, ++ &out); ++ if (rc != TPM_RC_SUCCESS) ++ return rc; ++ if (responseCode != TPM_RC_SUCCESS) ++ return responseCode; ++ ++ /* Unmarshal*/ ++ if (tag == TPM_ST_SESSIONS) ++ grub_tpm2_buffer_unpack_u32 (&out, ¶meterSize); ++ grub_tpm2_buffer_unpack_u32 (&out, pcrUpdateCounter); ++ grub_tpm2_mu_TPML_PCR_SELECTION_Unmarshal (&out, pcrSelectionOut); ++ grub_tpm2_mu_TPML_DIGEST_Unmarshal (&out, pcrValues); ++ if (tag == TPM_ST_SESSIONS) ++ grub_tpm2_mu_TPMS_AUTH_RESPONSE_Unmarshal (&out, authResponse); ++ if (out.error) ++ return TPM_RC_FAILURE; ++ ++ return TPM_RC_SUCCESS; ++} ++ ++TPM_RC ++TPM2_PolicyGetDigest (TPMI_SH_POLICY policySession, ++ const TPMS_AUTH_COMMAND *authCommand, ++ TPM2B_DIGEST *policyDigest, ++ TPMS_AUTH_RESPONSE *authResponse) ++{ ++ TPM_RC rc; ++ struct grub_tpm2_buffer in; ++ struct grub_tpm2_buffer out; ++ TPMS_AUTH_RESPONSE authResponseTmp; ++ TPM2B_DIGEST policyDigestTmp; ++ TPMI_ST_COMMAND_TAG tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS; ++ TPM_RC responseCode; ++ grub_uint32_t parameterSize; ++ ++ if (!authResponse) ++ authResponse = &authResponseTmp; ++ if (!policyDigest) ++ policyDigest = &policyDigestTmp; ++ ++ grub_memset (authResponse, 0, sizeof (*authResponse)); ++ grub_memset (policyDigest, 0, sizeof (*policyDigest)); ++ ++ /* Submit */ ++ grub_tpm2_buffer_init (&in); ++ grub_tpm2_buffer_pack_u32 (&in, policySession); ++ if (tag == TPM_ST_SESSIONS) ++ grub_tpm2_mu_TPMS_AUTH_COMMAND_Marshal (&in, authCommand); ++ if (in.error) ++ return TPM_RC_FAILURE; ++ ++ /* Submit */ ++ grub_tpm2_buffer_init (&out); ++ rc = grub_tpm2_submit_command (tag, TPM_CC_PolicyGetDigest, &responseCode, ++ &in, &out); ++ if (rc != TPM_RC_SUCCESS) ++ return rc; ++ if (responseCode != TPM_RC_SUCCESS) ++ return responseCode; ++ ++ /* Unmarshal*/ ++ if (tag == TPM_ST_SESSIONS) ++ grub_tpm2_buffer_unpack_u32 (&out, ¶meterSize); ++ grub_tpm2_mu_TPM2B_Unmarshal (&out, (TPM2B*)policyDigest); ++ if (tag == TPM_ST_SESSIONS) ++ grub_tpm2_mu_TPMS_AUTH_RESPONSE_Unmarshal (&out, authResponse); ++ if (out.error) ++ return TPM_RC_FAILURE; ++ ++ return TPM_RC_SUCCESS; ++} ++ ++TPM_RC ++TPM2_Create (TPMI_DH_OBJECT parentHandle, ++ const TPMS_AUTH_COMMAND *authCommand, ++ TPM2B_SENSITIVE_CREATE *inSensitive, ++ TPM2B_PUBLIC *inPublic, ++ TPM2B_DATA *outsideInfo, ++ TPML_PCR_SELECTION *creationPCR, ++ TPM2B_PRIVATE *outPrivate, ++ TPM2B_PUBLIC *outPublic, ++ TPM2B_CREATION_DATA *creationData, ++ TPM2B_DIGEST *creationHash, ++ TPMT_TK_CREATION *creationTicket, ++ TPMS_AUTH_RESPONSE *authResponse) ++{ ++ struct grub_tpm2_buffer in; ++ struct grub_tpm2_buffer out; ++ TPM2B_PUBLIC outPublicTmp; ++ TPM2B_PRIVATE outPrivateTmp; ++ TPM2B_CREATION_DATA creationDataTmp; ++ TPM2B_DIGEST creationHashTmp; ++ TPMT_TK_CREATION creationTicketTmp; ++ TPMS_AUTH_RESPONSE authResponseTmp; ++ TPMI_ST_COMMAND_TAG tag = authCommand ? TPM_ST_SESSIONS:TPM_ST_NO_SESSIONS; ++ TPM_RC responseCode; ++ TPM_RC rc; ++ grub_uint32_t parameterSize; ++ ++ if (!outPrivate) ++ outPrivate = &outPrivateTmp; ++ if (!outPublic) ++ outPublic = &outPublicTmp; ++ if (!creationData) ++ creationData = &creationDataTmp; ++ if (!creationHash) ++ creationHash = &creationHashTmp; ++ if (!creationTicket) ++ creationTicket = &creationTicketTmp; ++ if (!authResponse) ++ authResponse = &authResponseTmp; ++ ++ grub_memset (outPrivate, 0, sizeof (*outPrivate)); ++ grub_memset (outPublic, 0, sizeof (*outPublic)); ++ grub_memset (creationData, 0, sizeof (*creationData)); ++ grub_memset (creationHash, 0, sizeof (*creationHash)); ++ grub_memset (creationTicket, 0, sizeof (*creationTicket)); ++ grub_memset (authResponse, 0, sizeof (*authResponse)); ++ ++ /* Marshal */ ++ grub_tpm2_buffer_init (&in); ++ grub_tpm2_buffer_pack_u32 (&in, parentHandle); ++ if (authCommand) ++ grub_tpm2_mu_TPMS_AUTH_COMMAND_Marshal (&in, authCommand); ++ grub_tpm2_mu_TPM2B_SENSITIVE_CREATE_Marshal (&in, inSensitive); ++ grub_tpm2_mu_TPM2B_PUBLIC_Marshal (&in, inPublic); ++ grub_tpm2_mu_TPM2B_Marshal (&in, outsideInfo->size, outsideInfo->buffer); ++ grub_tpm2_mu_TPML_PCR_SELECTION_Marshal (&in, creationPCR); ++ if (in.error) ++ return TPM_RC_FAILURE; ++ ++ /* Submit */ ++ grub_tpm2_buffer_init (&out); ++ rc = grub_tpm2_submit_command (tag, TPM_CC_Create, &responseCode, &in, ++ &out); ++ if (rc != TPM_RC_SUCCESS) ++ return rc; ++ if (responseCode != TPM_RC_SUCCESS) ++ return responseCode; ++ ++ /* Unmarshal*/ ++ if (tag == TPM_ST_SESSIONS) ++ grub_tpm2_buffer_unpack_u32 (&out, ¶meterSize); ++ grub_tpm2_mu_TPM2B_Unmarshal (&out, (TPM2B*)outPrivate); ++ grub_tpm2_mu_TPM2B_PUBLIC_Unmarshal (&out, outPublic); ++ grub_tpm2_mu_TPM2B_Unmarshal (&out, (TPM2B*)creationData); ++ grub_tpm2_mu_TPM2B_Unmarshal (&out, (TPM2B*)creationHash); ++ grub_tpm2_mu_TPMT_TK_CREATION_Unmarshal (&out, creationTicket); ++ if (tag == TPM_ST_SESSIONS) ++ grub_tpm2_mu_TPMS_AUTH_RESPONSE_Unmarshal(&out, authResponse); ++ if (out.error) ++ return TPM_RC_FAILURE; ++ ++ return TPM_RC_SUCCESS; ++} ++ ++TPM_RC ++TPM2_EvictControl (TPMI_RH_PROVISION auth, ++ TPMI_DH_OBJECT objectHandle, ++ TPMI_DH_PERSISTENT persistentHandle, ++ const TPMS_AUTH_COMMAND *authCommand, ++ TPMS_AUTH_RESPONSE *authResponse) ++{ ++ struct grub_tpm2_buffer in; ++ struct grub_tpm2_buffer out; ++ TPMS_AUTH_RESPONSE authResponseTmp; ++ TPMI_ST_COMMAND_TAG tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS; ++ TPM_RC responseCode; ++ TPM_RC rc; ++ grub_uint32_t parameterSize; ++ ++ if (!authResponse) ++ authResponse = &authResponseTmp; ++ ++ grub_memset (authResponse, 0, sizeof (*authResponse)); ++ ++ /* Marshal */ ++ grub_tpm2_buffer_init (&in); ++ grub_tpm2_buffer_pack_u32 (&in, auth); ++ grub_tpm2_buffer_pack_u32 (&in, objectHandle); ++ if (authCommand) ++ grub_tpm2_mu_TPMS_AUTH_COMMAND_Marshal (&in, authCommand); ++ grub_tpm2_buffer_pack_u32 (&in, persistentHandle); ++ if (in.error) ++ return TPM_RC_FAILURE; ++ ++ /* Submit */ ++ grub_tpm2_buffer_init (&out); ++ rc = grub_tpm2_submit_command (tag, TPM_CC_EvictControl, &responseCode, &in, ++ &out); ++ if (rc != TPM_RC_SUCCESS) ++ return rc; ++ if (responseCode != TPM_RC_SUCCESS) ++ return responseCode; ++ ++ /* Unmarshal*/ ++ if (tag == TPM_ST_SESSIONS) ++ { ++ grub_tpm2_buffer_unpack_u32 (&out, ¶meterSize); ++ grub_tpm2_mu_TPMS_AUTH_RESPONSE_Unmarshal(&out, authResponse); ++ } ++ if (out.error) ++ return TPM_RC_FAILURE; ++ ++ return TPM_RC_SUCCESS; ++} +diff --git a/include/grub/tpm2/buffer.h b/include/grub/tpm2/buffer.h +new file mode 100644 +index 0000000000..ad05393add +--- /dev/null ++++ b/include/grub/tpm2/buffer.h +@@ -0,0 +1,65 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2022 Microsoft Corporation ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#ifndef GRUB_TPM2_BUFFER_HEADER ++#define GRUB_TPM2_BUFFER_HEADER 1 ++ ++#include ++ ++#define GRUB_TPM2_BUFFER_CAPACITY 4096 ++ ++struct grub_tpm2_buffer ++{ ++ grub_uint8_t data[GRUB_TPM2_BUFFER_CAPACITY]; ++ grub_size_t size; ++ grub_size_t offset; ++ grub_size_t cap; ++ int error; ++}; ++typedef struct grub_tpm2_buffer *grub_tpm2_buffer_t; ++ ++void ++grub_tpm2_buffer_init (grub_tpm2_buffer_t buffer); ++ ++void ++grub_tpm2_buffer_pack (grub_tpm2_buffer_t buffer, const void* data, ++ grub_size_t size); ++ ++void ++grub_tpm2_buffer_pack_u8 (grub_tpm2_buffer_t buffer, grub_uint8_t value); ++ ++void ++grub_tpm2_buffer_pack_u16 (grub_tpm2_buffer_t buffer, grub_uint16_t value); ++ ++void ++grub_tpm2_buffer_pack_u32 (grub_tpm2_buffer_t buffer, grub_uint32_t value); ++ ++void ++grub_tpm2_buffer_unpack (grub_tpm2_buffer_t buffer, void* data, ++ grub_size_t size); ++ ++void ++grub_tpm2_buffer_unpack_u8 (grub_tpm2_buffer_t buffer, grub_uint8_t* value); ++ ++void ++grub_tpm2_buffer_unpack_u16 (grub_tpm2_buffer_t buffer, grub_uint16_t* value); ++ ++void ++grub_tpm2_buffer_unpack_u32 (grub_tpm2_buffer_t buffer, grub_uint32_t* value); ++ ++#endif /* ! GRUB_TPM2_BUFFER_HEADER */ +diff --git a/include/grub/tpm2/internal/functions.h b/include/grub/tpm2/internal/functions.h +new file mode 100644 +index 0000000000..a1c71fae51 +--- /dev/null ++++ b/include/grub/tpm2/internal/functions.h +@@ -0,0 +1,117 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2022 Microsoft Corporation ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#ifndef GRUB_TPM2_INTERNAL_FUNCTIONS_HEADER ++#define GRUB_TPM2_INTERNAL_FUNCTIONS_HEADER 1 ++ ++#include ++ ++TPM_RC ++TPM2_CreatePrimary (TPMI_RH_HIERARCHY primaryHandle, ++ const TPMS_AUTH_COMMAND *authCommand, ++ TPM2B_SENSITIVE_CREATE *inSensitive, ++ TPM2B_PUBLIC *inPublic, ++ TPM2B_DATA *outsideInfo, ++ TPML_PCR_SELECTION *creationPCR, ++ TPM_HANDLE *objectHandle, ++ TPM2B_PUBLIC *outPublic, ++ TPM2B_CREATION_DATA *creationData, ++ TPM2B_DIGEST *creationHash, ++ TPMT_TK_CREATION *creationTicket, ++ TPM2B_NAME *name, ++ TPMS_AUTH_RESPONSE *authResponse); ++ ++TPM_RC ++TPM2_StartAuthSession (TPMI_DH_OBJECT tpmKey, ++ TPMI_DH_ENTITY bind, ++ const TPMS_AUTH_COMMAND *authCommand, ++ TPM2B_NONCE *nonceCaller, ++ TPM2B_ENCRYPTED_SECRET *encryptedSalt, ++ TPM_SE sessionType, ++ TPMT_SYM_DEF *symmetric, ++ TPMI_ALG_HASH authHash, ++ TPMI_SH_AUTH_SESSION *sessionHandle, ++ TPM2B_NONCE *nonceTpm, ++ TPMS_AUTH_RESPONSE *authResponse); ++ ++TPM_RC ++TPM2_PolicyPCR (TPMI_SH_POLICY policySession, ++ const TPMS_AUTH_COMMAND *authCommand, ++ TPM2B_DIGEST *pcrDigest, ++ TPML_PCR_SELECTION *pcrs, ++ TPMS_AUTH_RESPONSE *authResponse); ++ ++TPM_RC ++TPM2_ReadPublic (TPMI_DH_OBJECT objectHandle, ++ const TPMS_AUTH_COMMAND* authCommand, ++ TPM2B_PUBLIC *outPublic); ++ ++TPM_RC ++TPM2_Load (TPMI_DH_OBJECT parent_handle, ++ TPMS_AUTH_COMMAND const *authCommand, ++ TPM2B_PRIVATE *inPrivate, ++ TPM2B_PUBLIC *inPublic, ++ TPM_HANDLE *objectHandle, ++ TPM2B_NAME *name, ++ TPMS_AUTH_RESPONSE *authResponse); ++ ++TPM_RC ++TPM2_Unseal (TPMI_DH_OBJECT item_handle, ++ const TPMS_AUTH_COMMAND *authCommand, ++ TPM2B_SENSITIVE_DATA *outData, ++ TPMS_AUTH_RESPONSE *authResponse); ++ ++TPM_RC ++TPM2_FlushContext (TPMI_DH_CONTEXT handle); ++ ++TPM_RC ++TPM2_PCR_Read (const TPMS_AUTH_COMMAND *authCommand, ++ TPML_PCR_SELECTION *pcrSelectionIn, ++ grub_uint32_t *pcrUpdateCounter, ++ TPML_PCR_SELECTION *pcrSelectionOut, ++ TPML_DIGEST *pcrValues, ++ TPMS_AUTH_RESPONSE *authResponse); ++ ++TPM_RC ++TPM2_PolicyGetDigest (TPMI_SH_POLICY policySession, ++ const TPMS_AUTH_COMMAND *authCommand, ++ TPM2B_DIGEST *policyDigest, ++ TPMS_AUTH_RESPONSE *authResponse); ++ ++TPM_RC ++TPM2_Create (TPMI_DH_OBJECT parentHandle, ++ const TPMS_AUTH_COMMAND *authCommand, ++ TPM2B_SENSITIVE_CREATE *inSensitive, ++ TPM2B_PUBLIC *inPublic, ++ TPM2B_DATA *outsideInfo, ++ TPML_PCR_SELECTION *creationPCR, ++ TPM2B_PRIVATE *outPrivate, ++ TPM2B_PUBLIC *outPublic, ++ TPM2B_CREATION_DATA *creationData, ++ TPM2B_DIGEST *creationHash, ++ TPMT_TK_CREATION *creationTicket, ++ TPMS_AUTH_RESPONSE *authResponse); ++ ++TPM_RC ++TPM2_EvictControl (TPMI_RH_PROVISION auth, ++ TPMI_DH_OBJECT objectHandle, ++ TPMI_DH_PERSISTENT persistentHandle, ++ const TPMS_AUTH_COMMAND *authCommand, ++ TPMS_AUTH_RESPONSE *authResponse); ++ ++#endif /* ! GRUB_TPM2_INTERNAL_FUNCTIONS_HEADER */ +diff --git a/include/grub/tpm2/internal/structs.h b/include/grub/tpm2/internal/structs.h +new file mode 100644 +index 0000000000..75bf99ec8a +--- /dev/null ++++ b/include/grub/tpm2/internal/structs.h +@@ -0,0 +1,675 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2022 Microsoft Corporation ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#ifndef GRUB_TPM2_INTERNAL_STRUCTS_HEADER ++#define GRUB_TPM2_INTERNAL_STRUCTS_HEADER 1 ++ ++#include ++ ++/* TPMS_TAGGED_PROPERTY Structure */ ++struct TPMS_TAGGED_PROPERTY ++{ ++ TPM_PT property; ++ grub_uint32_t value; ++}; ++typedef struct TPMS_TAGGED_PROPERTY TPMS_TAGGED_PROPERTY; ++ ++/* TPML_TAGGED_TPM_PROPERTY Structure */ ++struct TPML_TAGGED_TPM_PROPERTY ++{ ++ grub_uint32_t count; ++ TPMS_TAGGED_PROPERTY tpmProperty[TPM_MAX_TPM_PROPERTIES]; ++}; ++typedef struct TPML_TAGGED_TPM_PROPERTY TPML_TAGGED_TPM_PROPERTY; ++ ++/* TPMU_CAPABILITIES Structure */ ++union TPMU_CAPABILITIES ++{ ++ TPML_TAGGED_TPM_PROPERTY tpmProperties; ++}; ++typedef union TPMU_CAPABILITIES TPMU_CAPABILITIES; ++ ++/* TPMS_CAPABILITY_DATA Structure */ ++struct TPMS_CAPABILITY_DATA ++{ ++ TPM_CAP capability; ++ TPMU_CAPABILITIES data; ++}; ++typedef struct TPMS_CAPABILITY_DATA TPMS_CAPABILITY_DATA; ++ ++/* TPMS_PCR_SELECT Structure */ ++struct TPMS_PCR_SELECT ++{ ++ grub_uint8_t sizeOfSelect; ++ grub_uint8_t pcrSelect[TPM_PCR_SELECT_MAX]; ++}; ++typedef struct TPMS_PCR_SELECT TPMS_PCR_SELECT; ++ ++/* TPMS_PCR_SELECTION Structure */ ++struct TPMS_PCR_SELECTION ++{ ++ TPMI_ALG_HASH hash; ++ grub_uint8_t sizeOfSelect; ++ grub_uint8_t pcrSelect[TPM_PCR_SELECT_MAX]; ++}; ++typedef struct TPMS_PCR_SELECTION TPMS_PCR_SELECTION; ++ ++static inline void TPMS_PCR_SELECTION_SelectPCR(TPMS_PCR_SELECTION* self, grub_uint32_t n) ++{ ++ self->pcrSelect[(n / 8)] |= (1 << (n % 8)); ++} ++ ++/* TPML_PCR_SELECTION Structure */ ++struct TPML_PCR_SELECTION ++{ ++ grub_uint32_t count; ++ TPMS_PCR_SELECTION pcrSelections[TPM_NUM_PCR_BANKS]; ++}; ++typedef struct TPML_PCR_SELECTION TPML_PCR_SELECTION; ++ ++/* TPMU_HA Structure */ ++union TPMU_HA ++{ ++ grub_uint8_t sha1[TPM_SHA1_DIGEST_SIZE]; ++ grub_uint8_t sha256[TPM_SHA256_DIGEST_SIZE]; ++ grub_uint8_t sha384[TPM_SHA384_DIGEST_SIZE]; ++ grub_uint8_t sha512[TPM_SHA512_DIGEST_SIZE]; ++ grub_uint8_t sm3_256[TPM_SM3_256_DIGEST_SIZE]; ++}; ++typedef union TPMU_HA TPMU_HA; ++ ++/* TPM2B Structure */ ++struct TPM2B ++{ ++ grub_uint16_t size; ++ grub_uint8_t buffer[1]; ++}; ++typedef struct TPM2B TPM2B; ++ ++/* TPM2B_DIGEST Structure */ ++struct TPM2B_DIGEST ++{ ++ grub_uint16_t size; ++ grub_uint8_t buffer[sizeof(TPMU_HA)]; ++}; ++typedef struct TPM2B_DIGEST TPM2B_DIGEST; ++ ++/* TPML_DIGEST Structure */ ++struct TPML_DIGEST ++{ ++ grub_uint32_t count; ++ TPM2B_DIGEST digests[8]; ++}; ++typedef struct TPML_DIGEST TPML_DIGEST; ++ ++/* TPM2B_NONCE Type */ ++typedef TPM2B_DIGEST TPM2B_NONCE; ++ ++/* TPMA_SESSION Structure */ ++struct TPMA_SESSION ++{ ++ unsigned int continueSession:1; ++ unsigned int auditExclusive:1; ++ unsigned int auditReset:1; ++ unsigned int reserved1:2; ++ unsigned int decrypt:1; ++ unsigned int encrypt:1; ++ unsigned int audit:1; ++ unsigned int reserved:24; ++}; ++typedef struct TPMA_SESSION TPMA_SESSION; ++ ++/* TPM2B_AUTH Type */ ++typedef TPM2B_DIGEST TPM2B_AUTH; ++ ++/* TPMS_AUTH_COMMAND Structure */ ++struct TPMS_AUTH_COMMAND ++{ ++ TPMI_SH_AUTH_SESSION sessionHandle; ++ TPM2B_NONCE nonce; ++ TPMA_SESSION sessionAttributes; ++ TPM2B_AUTH hmac; ++}; ++typedef struct TPMS_AUTH_COMMAND TPMS_AUTH_COMMAND; ++ ++/* TPMS_AUTH_RESPONSE Structure */ ++struct TPMS_AUTH_RESPONSE ++{ ++ TPM2B_NONCE nonce; ++ TPMA_SESSION sessionAttributes; ++ TPM2B_AUTH hmac; ++}; ++typedef struct TPMS_AUTH_RESPONSE TPMS_AUTH_RESPONSE; ++ ++/* TPM2B_SENSITIVE_DATA Structure */ ++struct TPM2B_SENSITIVE_DATA ++{ ++ grub_uint16_t size; ++ grub_uint8_t buffer[TPM_MAX_SYM_DATA]; ++}; ++typedef struct TPM2B_SENSITIVE_DATA TPM2B_SENSITIVE_DATA; ++ ++/* TPMS_SENSITIVE_CREATE Structure */ ++struct TPMS_SENSITIVE_CREATE ++{ ++ TPM2B_AUTH userAuth; ++ TPM2B_SENSITIVE_DATA data; ++}; ++typedef struct TPMS_SENSITIVE_CREATE TPMS_SENSITIVE_CREATE; ++ ++/* TPM2B_SENSITIVE_CREATE Structure */ ++struct TPM2B_SENSITIVE_CREATE ++{ ++ grub_uint16_t size; ++ TPMS_SENSITIVE_CREATE sensitive; ++}; ++typedef struct TPM2B_SENSITIVE_CREATE TPM2B_SENSITIVE_CREATE; ++ ++/* TPMA_OBJECT Structure */ ++struct TPMA_OBJECT ++{ ++ unsigned int reserved1:1; ++ unsigned int fixedTPM:1; ++ unsigned int stClear:1; ++ unsigned int reserved2:1; ++ unsigned int fixedParent:1; ++ unsigned int sensitiveDataOrigin:1; ++ unsigned int userWithAuth:1; ++ unsigned int adminWithPolicy:1; ++ unsigned int reserved3:2; ++ unsigned int noDA:1; ++ unsigned int encryptedDuplication:1; ++ unsigned int reserved4:4; ++ unsigned int restricted:1; ++ unsigned int decrypt:1; ++ unsigned int sign:1; ++ unsigned int reserved5:13; ++}; ++typedef struct TPMA_OBJECT TPMA_OBJECT; ++ ++/* TPMS_SCHEME_HASH Structure */ ++struct TPMS_SCHEME_HASH ++{ ++ TPMI_ALG_HASH hashAlg; ++}; ++typedef struct TPMS_SCHEME_HASH TPMS_SCHEME_HASH; ++ ++/* TPMS_SCHEME_HASH Types */ ++typedef TPMS_SCHEME_HASH TPMS_KEY_SCHEME_ECDH; ++typedef TPMS_SCHEME_HASH TPMS_KEY_SCHEME_ECMQV; ++typedef TPMS_SCHEME_HASH TPMS_SIG_SCHEME_RSASSA; ++typedef TPMS_SCHEME_HASH TPMS_SIG_SCHEME_RSAPSS; ++typedef TPMS_SCHEME_HASH TPMS_SIG_SCHEME_ECDSA; ++typedef TPMS_SCHEME_HASH TPMS_SIG_SCHEME_ECDAA; ++typedef TPMS_SCHEME_HASH TPMS_SIG_SCHEME_SM2; ++typedef TPMS_SCHEME_HASH TPMS_SIG_SCHEME_ECSCHNORR; ++typedef TPMS_SCHEME_HASH TPMS_ENC_SCHEME_RSAES; ++typedef TPMS_SCHEME_HASH TPMS_ENC_SCHEME_OAEP; ++typedef TPMS_SCHEME_HASH TPMS_SCHEME_KDF2; ++typedef TPMS_SCHEME_HASH TPMS_SCHEME_MGF1; ++typedef TPMS_SCHEME_HASH TPMS_SCHEME_KDF1_SP800_56A; ++typedef TPMS_SCHEME_HASH TPMS_SCHEME_KDF2; ++typedef TPMS_SCHEME_HASH TPMS_SCHEME_KDF1_SP800_108; ++ ++/* TPMS_SCHEME_HMAC Type */ ++typedef TPMS_SCHEME_HASH TPMS_SCHEME_HMAC; ++ ++/* TPMS_SCHEME_XOR Structure */ ++struct TPMS_SCHEME_XOR ++{ ++ TPMI_ALG_HASH hashAlg; ++ TPMI_ALG_KDF kdf; ++}; ++typedef struct TPMS_SCHEME_XOR TPMS_SCHEME_XOR; ++ ++/* TPMU_SCHEME_KEYEDHASH Union */ ++union TPMU_SCHEME_KEYEDHASH ++{ ++ TPMS_SCHEME_HMAC hmac; ++ TPMS_SCHEME_XOR exclusiveOr; ++}; ++typedef union TPMU_SCHEME_KEYEDHASH TPMU_SCHEME_KEYEDHASH; ++ ++/* TPMT_KEYEDHASH_SCHEME Structure */ ++struct TPMT_KEYEDHASH_SCHEME ++{ ++ TPMI_ALG_KEYEDHASH_SCHEME scheme; ++ TPMU_SCHEME_KEYEDHASH details; ++}; ++typedef struct TPMT_KEYEDHASH_SCHEME TPMT_KEYEDHASH_SCHEME; ++ ++/* TPMS_KEYEDHASH_PARMS Structure */ ++struct TPMS_KEYEDHASH_PARMS ++{ ++ TPMT_KEYEDHASH_SCHEME scheme; ++}; ++typedef struct TPMS_KEYEDHASH_PARMS TPMS_KEYEDHASH_PARMS; ++ ++/* TPMU_SYM_KEY_BITS Union */ ++union TPMU_SYM_KEY_BITS ++{ ++ TPM_KEY_BITS aes; ++ TPM_KEY_BITS exclusiveOr; ++ TPM_KEY_BITS sm4; ++ TPM_KEY_BITS camellia; ++}; ++typedef union TPMU_SYM_KEY_BITS TPMU_SYM_KEY_BITS; ++ ++/* TPMU_SYM_MODE Union */ ++union TPMU_SYM_MODE ++{ ++ TPMI_ALG_SYM_MODE aes; ++ TPMI_ALG_SYM_MODE sm4; ++ TPMI_ALG_SYM_MODE camellia; ++ TPMI_ALG_SYM_MODE sym; ++}; ++typedef union TPMU_SYM_MODE TPMU_SYM_MODE; ++ ++/* TPMT_SYM_DEF_OBJECT Structure */ ++struct TPMT_SYM_DEF_OBJECT ++{ ++ TPMI_ALG_SYM_OBJECT algorithm; ++ TPMU_SYM_KEY_BITS keyBits; ++ TPMU_SYM_MODE mode; ++}; ++typedef struct TPMT_SYM_DEF_OBJECT TPMT_SYM_DEF_OBJECT; ++ ++/* TPMS_SYMCIPHER_PARMS Structure */ ++struct TPMS_SYMCIPHER_PARMS ++{ ++ TPMT_SYM_DEF_OBJECT sym; ++}; ++typedef struct TPMS_SYMCIPHER_PARMS TPMS_SYMCIPHER_PARMS; ++ ++/* TPMU_ASYM_SCHEME Union */ ++union TPMU_ASYM_SCHEME ++{ ++ TPMS_KEY_SCHEME_ECDH ecdh; ++ TPMS_KEY_SCHEME_ECMQV ecmqv; ++ TPMS_SIG_SCHEME_RSASSA rsassa; ++ TPMS_SIG_SCHEME_RSAPSS rsapss; ++ TPMS_SIG_SCHEME_ECDSA ecdsa; ++ TPMS_SIG_SCHEME_ECDAA ecdaa; ++ TPMS_SIG_SCHEME_SM2 sm2; ++ TPMS_SIG_SCHEME_ECSCHNORR ecschnorr; ++ TPMS_ENC_SCHEME_RSAES rsaes; ++ TPMS_ENC_SCHEME_OAEP oaep; ++ TPMS_SCHEME_HASH anySig; ++ unsigned char padding[4]; ++}; ++typedef union TPMU_ASYM_SCHEME TPMU_ASYM_SCHEME; ++ ++/* TPMT_RSA_SCHEME Structure */ ++struct TPMT_RSA_SCHEME ++{ ++ TPMI_ALG_RSA_SCHEME scheme; ++ TPMU_ASYM_SCHEME details; ++}; ++typedef struct TPMT_RSA_SCHEME TPMT_RSA_SCHEME; ++ ++/* TPMS_RSA_PARMS Structure */ ++struct TPMS_RSA_PARMS ++{ ++ TPMT_SYM_DEF_OBJECT symmetric; ++ TPMT_RSA_SCHEME scheme; ++ TPM_KEY_BITS keyBits; ++ grub_uint32_t exponent; ++}; ++typedef struct TPMS_RSA_PARMS TPMS_RSA_PARMS; ++ ++/* TPMT_ECC_SCHEME Structure */ ++struct TPMT_ECC_SCHEME ++{ ++ TPMI_ALG_ECC_SCHEME scheme; ++ TPMU_ASYM_SCHEME details; ++}; ++typedef struct TPMT_ECC_SCHEME TPMT_ECC_SCHEME; ++ ++/* TPMU_KDF_SCHEME Union */ ++union TPMU_KDF_SCHEME ++{ ++ TPMS_SCHEME_MGF1 mgf1; ++ TPMS_SCHEME_KDF1_SP800_56A kdf1_sp800_56a; ++ TPMS_SCHEME_KDF2 kdf2; ++ TPMS_SCHEME_KDF1_SP800_108 kdf1_sp800_108; ++}; ++typedef union TPMU_KDF_SCHEME TPMU_KDF_SCHEME; ++ ++/* TPMT_KDF_SCHEME Structure */ ++struct TPMT_KDF_SCHEME ++{ ++ TPMI_ALG_KDF scheme; ++ TPMU_KDF_SCHEME details; ++}; ++typedef struct TPMT_KDF_SCHEME TPMT_KDF_SCHEME; ++ ++/* TPMS_ECC_PARMS Structure */ ++struct TPMS_ECC_PARMS ++{ ++ TPMT_SYM_DEF_OBJECT symmetric; ++ TPMT_ECC_SCHEME scheme; ++ TPMI_ECC_CURVE curveID; ++ TPMT_KDF_SCHEME kdf; ++}; ++typedef struct TPMS_ECC_PARMS TPMS_ECC_PARMS; ++ ++/* TPMT_ASYM_SCHEME Structure */ ++struct TPMT_ASYM_SCHEME ++{ ++ TPMI_ALG_ASYM_SCHEME scheme; ++ TPMU_ASYM_SCHEME details; ++}; ++typedef struct TPMT_ASYM_SCHEME TPMT_ASYM_SCHEME; ++ ++/* TPMS_ASYM_PARMS Structure */ ++struct TPMS_ASYM_PARMS ++{ ++ TPMT_SYM_DEF_OBJECT symmetric; ++ TPMT_ASYM_SCHEME scheme; ++}; ++typedef struct TPMS_ASYM_PARMS TPMS_ASYM_PARMS; ++ ++/* TPMU_PUBLIC_PARMS Union */ ++union TPMU_PUBLIC_PARMS ++{ ++ TPMS_KEYEDHASH_PARMS keyedHashDetail; ++ TPMS_SYMCIPHER_PARMS symDetail; ++ TPMS_RSA_PARMS rsaDetail; ++ TPMS_ECC_PARMS eccDetail; ++ TPMS_ASYM_PARMS asymDetail; ++}; ++typedef union TPMU_PUBLIC_PARMS TPMU_PUBLIC_PARMS; ++ ++/* TPM2B_PUBLIC_KEY_RSA Structure */ ++struct TPM2B_PUBLIC_KEY_RSA ++{ ++ grub_uint16_t size; ++ grub_uint8_t buffer[TPM_MAX_RSA_KEY_BYTES]; ++}; ++typedef struct TPM2B_PUBLIC_KEY_RSA TPM2B_PUBLIC_KEY_RSA; ++ ++/* TPM2B_ECC_PARAMETER Structure */ ++struct TPM2B_ECC_PARAMETER ++{ ++ grub_uint16_t size; ++ grub_uint8_t buffer[TPM_MAX_ECC_KEY_BYTES]; ++}; ++typedef struct TPM2B_ECC_PARAMETER TPM2B_ECC_PARAMETER; ++ ++/* TPMS_ECC_POINT Structure */ ++struct TPMS_ECC_POINT ++{ ++ TPM2B_ECC_PARAMETER x; ++ TPM2B_ECC_PARAMETER y; ++}; ++typedef struct TPMS_ECC_POINT TPMS_ECC_POINT; ++ ++/* TPMU_ENCRYPTED_SECRET Union */ ++union TPMU_ENCRYPTED_SECRET ++{ ++ grub_uint8_t ecc[sizeof(TPMS_ECC_POINT)]; ++ grub_uint8_t rsa[TPM_MAX_RSA_KEY_BYTES]; ++ grub_uint8_t symmetric[sizeof(TPM2B_DIGEST)]; ++ grub_uint8_t keyedHash[sizeof(TPM2B_DIGEST)]; ++}; ++typedef union TPMU_ENCRYPTED_SECRET TPMU_ENCRYPTED_SECRET; ++ ++/* TPM2B_ENCRYPTED_SECRET Structure */ ++struct TPM2B_ENCRYPTED_SECRET ++{ ++ grub_uint16_t size; ++ grub_uint8_t secret[sizeof(TPMU_ENCRYPTED_SECRET)]; ++}; ++typedef struct TPM2B_ENCRYPTED_SECRET TPM2B_ENCRYPTED_SECRET; ++ ++/* TPMU_PUBLIC_ID Union */ ++union TPMU_PUBLIC_ID ++{ ++ TPM2B_DIGEST keyedHash; ++ TPM2B_DIGEST sym; ++ TPM2B_PUBLIC_KEY_RSA rsa; ++ TPMS_ECC_POINT ecc; ++}; ++typedef union TPMU_PUBLIC_ID TPMU_PUBLIC_ID; ++ ++/* TPMT_PUBLIC Structure */ ++struct TPMT_PUBLIC ++{ ++ TPMI_ALG_PUBLIC type; ++ TPMI_ALG_HASH nameAlg; ++ TPMA_OBJECT objectAttributes; ++ TPM2B_DIGEST authPolicy; ++ TPMU_PUBLIC_PARMS parameters; ++ TPMU_PUBLIC_ID unique; ++}; ++typedef struct TPMT_PUBLIC TPMT_PUBLIC; ++ ++/* TPM2B_PUBLIC Structure */ ++struct TPM2B_PUBLIC ++{ ++ grub_uint16_t size; ++ TPMT_PUBLIC publicArea; ++}; ++typedef struct TPM2B_PUBLIC TPM2B_PUBLIC; ++ ++/* TPMT_HA Structure */ ++struct TPMT_HA ++{ ++ TPMI_ALG_HASH hashAlg; ++ TPMU_HA digest; ++}; ++typedef struct TPMT_HA TPMT_HA; ++ ++/* TPM2B_DATA Structure */ ++struct TPM2B_DATA ++{ ++ grub_uint16_t size; ++ grub_uint8_t buffer[sizeof(TPMT_HA)]; ++}; ++typedef struct TPM2B_DATA TPM2B_DATA; ++ ++/* TPMA_LOCALITY Structure */ ++struct TPMA_LOCALITY ++{ ++ unsigned char TPM_LOC_ZERO:1; ++ unsigned char TPM_LOC_ONE:1; ++ unsigned char TPM_LOC_TWO:1; ++ unsigned char TPM_LOC_THREE:1; ++ unsigned char TPM_LOC_FOUR:1; ++ unsigned char Extended:3; ++}; ++typedef struct TPMA_LOCALITY TPMA_LOCALITY; ++ ++/* TPMU_NAME Union */ ++union TPMU_NAME ++{ ++ TPMT_HA digest; ++ TPM_HANDLE handle; ++}; ++typedef union TPMU_NAME TPMU_NAME; ++ ++/* TPM2B_NAME Structure */ ++struct TPM2B_NAME ++{ ++ grub_uint16_t size; ++ grub_uint8_t name[sizeof(TPMU_NAME)]; ++}; ++typedef struct TPM2B_NAME TPM2B_NAME; ++ ++/* TPMS_CREATION_DATA Structure */ ++struct TPMS_CREATION_DATA ++{ ++ TPML_PCR_SELECTION pcrSelect; ++ TPM2B_DIGEST pcrDigest; ++ TPMA_LOCALITY locality; ++ TPM_ALG_ID parentNameAlg; ++ TPM2B_NAME parentName; ++ TPM2B_NAME parentQualifiedName; ++ TPM2B_DATA outsideInfo; ++}; ++typedef struct TPMS_CREATION_DATA TPMS_CREATION_DATA; ++ ++/* TPM2B_CREATION_DATA Structure */ ++struct TPM2B_CREATION_DATA ++{ ++ grub_uint16_t size; ++ TPMS_CREATION_DATA creationData; ++}; ++typedef struct TPM2B_CREATION_DATA TPM2B_CREATION_DATA; ++ ++/* TPMT_SYM_DEF Structure */ ++struct TPMT_SYM_DEF ++{ ++ TPMI_ALG_SYM algorithm; ++ TPMU_SYM_KEY_BITS keyBits; ++ TPMU_SYM_MODE mode; ++}; ++typedef struct TPMT_SYM_DEF TPMT_SYM_DEF; ++ ++/* TPM2B_MAX_BUFFER Structure */ ++struct TPM2B_MAX_BUFFER ++{ ++ grub_uint16_t size; ++ grub_uint8_t buffer[TPM_MAX_DIGEST_BUFFER]; ++}; ++typedef struct TPM2B_MAX_BUFFER TPM2B_MAX_BUFFER; ++ ++/* TPMT_TK_HASHCHECK Structure */ ++struct TPMT_TK_HASHCHECK ++{ ++ TPM_ST tag; ++ TPMI_RH_HIERARCHY hierarchy; ++ TPM2B_DIGEST digest; ++}; ++typedef struct TPMT_TK_HASHCHECK TPMT_TK_HASHCHECK; ++ ++/* TPM2B_SYM_KEY Structure */ ++struct TPM2B_SYM_KEY ++{ ++ grub_uint16_t size; ++ grub_uint8_t buffer[TPM_MAX_SYM_KEY_BYTES]; ++}; ++typedef struct TPM2B_SYM_KEY TPM2B_SYM_KEY; ++ ++/* TPM2B_PRIVATE_KEY_RSA Structure */ ++struct TPM2B_PRIVATE_KEY_RSA ++{ ++ grub_uint16_t size; ++ grub_uint8_t buffer[TPM_MAX_RSA_KEY_BYTES/2]; ++}; ++typedef struct TPM2B_PRIVATE_KEY_RSA TPM2B_PRIVATE_KEY_RSA; ++ ++/* TPM2B_PRIVATE_VENDOR_SPECIFIC Structure */ ++struct TPM2B_PRIVATE_VENDOR_SPECIFIC ++{ ++ grub_uint16_t size; ++ grub_uint8_t buffer[TPM_PRIVATE_VENDOR_SPECIFIC_BYTES]; ++}; ++typedef struct TPM2B_PRIVATE_VENDOR_SPECIFIC TPM2B_PRIVATE_VENDOR_SPECIFIC; ++ ++/* TPM2B_PRIVATE_VENDOR_SPECIFIC Union */ ++union TPMU_SENSITIVE_COMPOSITE ++{ ++ TPM2B_PRIVATE_KEY_RSA rsa; ++ TPM2B_ECC_PARAMETER ecc; ++ TPM2B_SENSITIVE_DATA bits; ++ TPM2B_SYM_KEY sym; ++ TPM2B_PRIVATE_VENDOR_SPECIFIC any; ++}; ++typedef union TPMU_SENSITIVE_COMPOSITE TPMU_SENSITIVE_COMPOSITE; ++ ++/* TPMT_SENSITIVE Structure */ ++struct TPMT_SENSITIVE ++{ ++ TPMI_ALG_PUBLIC sensitiveType; ++ TPM2B_AUTH authValue; ++ TPM2B_DIGEST seedValue; ++ TPMU_SENSITIVE_COMPOSITE sensitive; ++}; ++typedef struct TPMT_SENSITIVE TPMT_SENSITIVE; ++ ++/* TPM2B_SENSITIVE Structure */ ++struct TPM2B_SENSITIVE ++{ ++ grub_uint16_t size; ++ TPMT_SENSITIVE sensitiveArea; ++}; ++typedef struct TPM2B_SENSITIVE TPM2B_SENSITIVE; ++ ++/* _PRIVATE Structure */ ++struct _PRIVATE ++{ ++ TPM2B_DIGEST integrityOuter; ++ TPM2B_DIGEST integrityInner; ++ TPM2B_SENSITIVE sensitive; ++}; ++typedef struct _PRIVATE _PRIVATE; ++ ++/* TPM2B_PRIVATE Structure */ ++struct TPM2B_PRIVATE ++{ ++ grub_uint16_t size; ++ grub_uint8_t buffer[sizeof(_PRIVATE)]; ++}; ++typedef struct TPM2B_PRIVATE TPM2B_PRIVATE; ++ ++/* TPML_DIGEST_VALUES Structure */ ++struct TPML_DIGEST_VALUES ++{ ++ grub_uint16_t count; ++ TPMT_HA digests[TPM_NUM_PCR_BANKS]; ++}; ++typedef struct TPML_DIGEST_VALUES TPML_DIGEST_VALUES; ++ ++/* TPM2B_MAX_NV_BUFFER Structure */ ++struct TPM2B_MAX_NV_BUFFER ++{ ++ grub_uint16_t size; ++ grub_uint8_t buffer[TPM_MAX_NV_BUFFER_SIZE]; ++}; ++typedef struct TPM2B_MAX_NV_BUFFER TPM2B_MAX_NV_BUFFER; ++ ++/* TPMS_NV_PUBLIC Structure */ ++struct TPMS_NV_PUBLIC ++{ ++ TPMI_RH_NV_INDEX nvIndex; ++ TPMI_ALG_HASH nameAlg; ++ TPMA_NV attributes; ++ TPM2B_DIGEST authPolicy; ++ grub_uint16_t dataSize; ++}; ++typedef struct TPMS_NV_PUBLIC TPMS_NV_PUBLIC; ++ ++/* TPM2B_NV_PUBLIC Structure */ ++struct TPM2B_NV_PUBLIC ++{ ++ grub_uint16_t size; ++ TPMS_NV_PUBLIC nvPublic; ++}; ++typedef struct TPM2B_NV_PUBLIC TPM2B_NV_PUBLIC; ++ ++/* TPMT_TK_CREATION Structure */ ++struct TPMT_TK_CREATION ++{ ++ TPM_ST tag; ++ TPMI_RH_HIERARCHY hierarchy; ++ TPM2B_DIGEST digest; ++}; ++typedef struct TPMT_TK_CREATION TPMT_TK_CREATION; ++ ++#endif /* ! GRUB_TPM2_INTERNAL_STRUCTS_HEADER */ +diff --git a/include/grub/tpm2/internal/types.h b/include/grub/tpm2/internal/types.h +new file mode 100644 +index 0000000000..9714f75d4f +--- /dev/null ++++ b/include/grub/tpm2/internal/types.h +@@ -0,0 +1,372 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2022 Microsoft Corporation ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#ifndef GRUB_TPM2_INTERNAL_TYPES_HEADER ++#define GRUB_TPM2_INTERNAL_TYPES_HEADER 1 ++ ++#include ++ ++/* TPM2_RC Constants */ ++typedef grub_uint32_t TPM_RC; ++ ++#define TPM_RC_1 ((TPM_RC) 0x100) ++#define TPM_RC_2 ((TPM_RC) 0x200) ++#define TPM_RC_3 ((TPM_RC) 0x300) ++#define TPM_RC_4 ((TPM_RC) 0x400) ++#define TPM_RC_5 ((TPM_RC) 0x500) ++#define TPM_RC_6 ((TPM_RC) 0x600) ++#define TPM_RC_7 ((TPM_RC) 0x700) ++#define TPM_RC_8 ((TPM_RC) 0x800) ++#define TPM_RC_9 ((TPM_RC) 0x900) ++#define TPM_RC_A ((TPM_RC) 0xA00) ++#define TPM_RC_ASYMMETRIC ((TPM_RC) 0x081) ++#define TPM_RC_ATTRIBUTES ((TPM_RC) 0x082) ++#define TPM_RC_AUTH_CONTEXT ((TPM_RC) 0x145) ++#define TPM_RC_AUTH_FAIL ((TPM_RC) 0x08E) ++#define TPM_RC_AUTH_MISSING ((TPM_RC) 0x125) ++#define TPM_RC_AUTHSIZE ((TPM_RC) 0x144) ++#define TPM_RC_AUTH_TYPE ((TPM_RC) 0x124) ++#define TPM_RC_AUTH_UNAVAILABLE ((TPM_RC) 0x12F) ++#define TPM_RC_B ((TPM_RC) 0xB00) ++#define TPM_RC_BAD_AUTH ((TPM_RC) 0x0A2) ++#define TPM_RC_BAD_CONTEXT ((TPM_RC) 0x150) ++#define TPM_RC_BAD_TAG ((TPM_RC) 0x01E) ++#define TPM_RC_BINDING ((TPM_RC) 0x0A5) ++#define TPM_RC_C ((TPM_RC) 0xC00) ++#define TPM_RC_CANCELED ((TPM_RC) 0x909) ++#define TPM_RC_COMMAND_CODE ((TPM_RC) 0x143) ++#define TPM_RC_COMMAND_SIZE ((TPM_RC) 0x142) ++#define TPM_RC_CONTEXT_GAP ((TPM_RC) 0x901) ++#define TPM_RC_CPHASH ((TPM_RC) 0x151) ++#define TPM_RC_CURVE ((TPM_RC) 0x0A6) ++#define TPM_RC_D ((TPM_RC) 0xD00) ++#define TPM_RC_DISABLED ((TPM_RC) 0x120) ++#define TPM_RC_E ((TPM_RC) 0xE00) ++#define TPM_RC_ECC_POINT ((TPM_RC) 0x0A7) ++#define TPM_RC_EXCLUSIVE ((TPM_RC) 0x121) ++#define TPM_RC_EXPIRED ((TPM_RC) 0x0A3) ++#define TPM_RC_F ((TPM_RC) 0xF00) ++#define TPM_RC_FAILURE ((TPM_RC) 0x101) ++#define TPM_RC_H ((TPM_RC) 0x000) ++#define TPM_RC_HANDLE ((TPM_RC) 0x08B) ++#define TPM_RC_HASH ((TPM_RC) 0x083) ++#define TPM_RC_HIERARCHY ((TPM_RC) 0x085) ++#define TPM_RC_HMAC ((TPM_RC) 0x119) ++#define TPM_RC_INITIALIZE ((TPM_RC) 0x100) ++#define TPM_RC_INSUFFICIENT ((TPM_RC) 0x09A) ++#define TPM_RC_INTEGRITY ((TPM_RC) 0x09F) ++#define TPM_RC_KDF ((TPM_RC) 0x08C) ++#define TPM_RC_KEY ((TPM_RC) 0x09C) ++#define TPM_RC_KEY_SIZE ((TPM_RC) 0x087) ++#define TPM_RC_LOCALITY ((TPM_RC) 0x907) ++#define TPM_RC_LOCKOUT ((TPM_RC) 0x921) ++#define TPM_RC_MEMORY ((TPM_RC) 0x904) ++#define TPM_RC_MGF ((TPM_RC) 0x088) ++#define TPM_RC_MODE ((TPM_RC) 0x089) ++#define TPM_RC_NEEDS_TEST ((TPM_RC) 0x153) ++#define TPM_RC_N_MASK ((TPM_RC) 0xF00) ++#define TPM_RC_NONCE ((TPM_RC) 0x08F) ++#define TPM_RC_NO_RESULT ((TPM_RC) 0x154) ++#define TPM_RC_NOT_USED ((TPM_RC) 0x97F) ++#define TPM_RC_NV_AUTHORIZATION ((TPM_RC) 0x149) ++#define TPM_RC_NV_DEFINED ((TPM_RC) 0x14C) ++#define TPM_RC_NV_LOCKED ((TPM_RC) 0x148) ++#define TPM_RC_NV_RANGE ((TPM_RC) 0x146) ++#define TPM_RC_NV_RATE ((TPM_RC) 0x920) ++#define TPM_RC_NV_SIZE ((TPM_RC) 0x147) ++#define TPM_RC_NV_SPACE ((TPM_RC) 0x14B) ++#define TPM_RC_NV_UNAVAILABLE ((TPM_RC) 0x923) ++#define TPM_RC_NV_UNINITIALIZED ((TPM_RC) 0x14A) ++#define TPM_RC_OBJECT_HANDLES ((TPM_RC) 0x906) ++#define TPM_RC_OBJECT_MEMORY ((TPM_RC) 0x902) ++#define TPM_RC_P ((TPM_RC) 0x040) ++#define TPM_RC_PARENT ((TPM_RC) 0x152) ++#define TPM_RC_PCR ((TPM_RC) 0x127) ++#define TPM_RC_PCR_CHANGED ((TPM_RC) 0x128) ++#define TPM_RC_POLICY ((TPM_RC) 0x126) ++#define TPM_RC_POLICY_CC ((TPM_RC) 0x0A4) ++#define TPM_RC_POLICY_FAIL ((TPM_RC) 0x09D) ++#define TPM_RC_PP ((TPM_RC) 0x090) ++#define TPM_RC_PRIVATE ((TPM_RC) 0x10B) ++#define TPM_RC_RANGE ((TPM_RC) 0x08D) ++#define TPM_RC_REBOOT ((TPM_RC) 0x130) ++#define TPM_RC_REFERENCE_H0 ((TPM_RC) 0x910) ++#define TPM_RC_REFERENCE_H1 ((TPM_RC) 0x911) ++#define TPM_RC_REFERENCE_H2 ((TPM_RC) 0x912) ++#define TPM_RC_REFERENCE_H3 ((TPM_RC) 0x913) ++#define TPM_RC_REFERENCE_H4 ((TPM_RC) 0x914) ++#define TPM_RC_REFERENCE_H5 ((TPM_RC) 0x915) ++#define TPM_RC_REFERENCE_H6 ((TPM_RC) 0x916) ++#define TPM_RC_REFERENCE_S0 ((TPM_RC) 0x918) ++#define TPM_RC_REFERENCE_S1 ((TPM_RC) 0x919) ++#define TPM_RC_REFERENCE_S2 ((TPM_RC) 0x91A) ++#define TPM_RC_REFERENCE_S3 ((TPM_RC) 0x91B) ++#define TPM_RC_REFERENCE_S4 ((TPM_RC) 0x91C) ++#define TPM_RC_REFERENCE_S5 ((TPM_RC) 0x91D) ++#define TPM_RC_REFERENCE_S6 ((TPM_RC) 0x91E) ++#define TPM_RC_RESERVED_BITS ((TPM_RC) 0x0A1) ++#define TPM_RC_RETRY ((TPM_RC) 0x922) ++#define TPM_RC_S ((TPM_RC) 0x800) ++#define TPM_RC_SCHEME ((TPM_RC) 0x092) ++#define TPM_RC_SELECTOR ((TPM_RC) 0x098) ++#define TPM_RC_SENSITIVE ((TPM_RC) 0x155) ++#define TPM_RC_SEQUENCE ((TPM_RC) 0x103) ++#define TPM_RC_SESSION_HANDLES ((TPM_RC) 0x905) ++#define TPM_RC_SESSION_MEMORY ((TPM_RC) 0x903) ++#define TPM_RC_SIGNATURE ((TPM_RC) 0x09B) ++#define TPM_RC_SIZE ((TPM_RC) 0x095) ++#define TPM_RC_SUCCESS ((TPM_RC) 0x000) ++#define TPM_RC_SYMMETRIC ((TPM_RC) 0x096) ++#define TPM_RC_TAG ((TPM_RC) 0x097) ++#define TPM_RC_TESTING ((TPM_RC) 0x90A) ++#define TPM_RC_TICKET ((TPM_RC) 0x0A0) ++#define TPM_RC_TOO_MANY_CONTEXTS ((TPM_RC) 0x12E) ++#define TPM_RC_TYPE ((TPM_RC) 0x08A) ++#define TPM_RC_UNBALANCED ((TPM_RC) 0x131) ++#define TPM_RC_UPGRADE ((TPM_RC) 0x12D) ++#define TPM_RC_VALUE ((TPM_RC) 0x084) ++#define TPM_RC_YIELDED ((TPM_RC) 0x908) ++ ++/* TPMA_NV Constants */ ++typedef grub_uint32_t TPMA_NV; ++ ++#define TPMA_NV_PPWRITE ((TPMA_NV) 0x00000001) ++#define TPMA_NV_OWNERWRITE ((TPMA_NV) 0x00000002) ++#define TPMA_NV_AUTHWRITE ((TPMA_NV) 0x00000004) ++#define TPMA_NV_POLICYWRITE ((TPMA_NV) 0x00000008) ++#define TPMA_NV_TPM2_NT_MASK ((TPMA_NV) 0x000000F0) ++#define TPMA_NV_TPM2_NT_SHIFT (4) ++#define TPMA_NV_RESERVED1_MASK ((TPMA_NV) 0x00000300) ++#define TPMA_NV_POLICY_DELETE ((TPMA_NV) 0x00000400) ++#define TPMA_NV_WRITELOCKED ((TPMA_NV) 0x00000800) ++#define TPMA_NV_WRITEALL ((TPMA_NV) 0x00001000) ++#define TPMA_NV_WRITEDEFINE ((TPMA_NV) 0x00002000) ++#define TPMA_NV_WRITE_STCLEAR ((TPMA_NV) 0x00004000) ++#define TPMA_NV_GLOBALLOCK ((TPMA_NV) 0x00008000) ++#define TPMA_NV_PPREAD ((TPMA_NV) 0x00010000) ++#define TPMA_NV_OWNERREAD ((TPMA_NV) 0x00020000) ++#define TPMA_NV_AUTHREAD ((TPMA_NV) 0x00040000) ++#define TPMA_NV_POLICYREAD ((TPMA_NV) 0x00080000) ++#define TPMA_NV_RESERVED2_MASK ((TPMA_NV) 0x01F00000) ++#define TPMA_NV_NO_DA ((TPMA_NV) 0x02000000) ++#define TPMA_NV_ORDERLY ((TPMA_NV) 0x04000000) ++#define TPMA_NV_CLEAR_STCLEAR ((TPMA_NV) 0x08000000) ++#define TPMA_NV_READLOCKED ((TPMA_NV) 0x10000000) ++#define TPMA_NV_WRITTEN ((TPMA_NV) 0x20000000) ++#define TPMA_NV_PLATFORMCREATE ((TPMA_NV) 0x40000000) ++#define TPMA_NV_READ_STCLEAR ((TPMA_NV) 0x80000000) ++ ++/* TPM_ALG_ID Constants */ ++typedef grub_uint16_t TPM_ALG_ID; ++ ++#define TPM_ALG_ERROR ((TPM_ALG_ID) 0x0000) ++#define TPM_ALG_AES ((TPM_ALG_ID) 0x0006) ++#define TPM_ALG_CAMELLIA ((TPM_ALG_ID) 0x0026) ++#define TPM_ALG_CBC ((TPM_ALG_ID) 0x0042) ++#define TPM_ALG_CFB ((TPM_ALG_ID) 0x0043) ++#define TPM_ALG_ECB ((TPM_ALG_ID) 0x0044) ++#define TPM_ALG_ECC ((TPM_ALG_ID) 0x0023) ++#define TPM_ALG_HMAC ((TPM_ALG_ID) 0x0005) ++#define TPM_ALG_KDF1_SP800_108 ((TPM_ALG_ID) 0x0022) ++#define TPM_ALG_KDF1_SP800_56A ((TPM_ALG_ID) 0x0020) ++#define TPM_ALG_KDF2 ((TPM_ALG_ID) 0x0021) ++#define TPM_ALG_KEYEDHASH ((TPM_ALG_ID) 0x0008) ++#define TPM_ALG_MGF1 ((TPM_ALG_ID) 0x0007) ++#define TPM_ALG_NULL ((TPM_ALG_ID) 0x0010) ++#define TPM_ALG_RSA ((TPM_ALG_ID) 0x0001) ++#define TPM_ALG_SHA1 ((TPM_ALG_ID) 0x0004) ++#define TPM_ALG_SHA256 ((TPM_ALG_ID) 0x000B) ++#define TPM_ALG_SHA384 ((TPM_ALG_ID) 0x000C) ++#define TPM_ALG_SHA512 ((TPM_ALG_ID) 0x000D) ++#define TPM_ALG_SM3_256 ((TPM_ALG_ID) 0x0012) ++#define TPM_ALG_SM4 ((TPM_ALG_ID) 0x0013) ++#define TPM_ALG_SYMCIPHER ((TPM_ALG_ID) 0x0025) ++#define TPM_ALG_XOR ((TPM_ALG_ID) 0x000A) ++ ++/* TPM_CAP Constants */ ++typedef grub_uint32_t TPM_CAP; ++ ++#define TPM_CAP_FIRST ((TPM_CAP) 0x00000000) ++#define TPM_CAP_ALGS ((TPM_CAP) 0x00000000) ++#define TPM_CAP_HANDLES ((TPM_CAP) 0x00000001) ++#define TPM_CAP_COMMANDS ((TPM_CAP) 0x00000002) ++#define TPM_CAP_PP_COMMANDS ((TPM_CAP) 0x00000003) ++#define TPM_CAP_AUDIT_COMMANDS ((TPM_CAP) 0x00000004) ++#define TPM_CAP_PCRS ((TPM_CAP) 0x00000005) ++#define TPM_CAP_TPM_PROPERTIES ((TPM_CAP) 0x00000006) ++#define TPM_CAP_PCR_PROPERTIES ((TPM_CAP) 0x00000007) ++#define TPM_CAP_ECC_CURVES ((TPM_CAP) 0x00000008) ++#define TPM_CAP_LAST ((TPM_CAP) 0x00000008) ++#define TPM_CAP_VENDOR_PROPERTY ((TPM_CAP) 0x00000100) ++ ++/* TPM_PT Constants */ ++typedef grub_uint32_t TPM_PT; ++ ++#define TPM_PT_NONE ((TPM_PT) 0x00000000) ++#define PT_GROUP ((TPM_PT) 0x00000100) ++#define PT_FIXED ((TPM_PT) (PT_GROUP * 1)) ++#define TPM_PT_FAMILY_INDICATOR ((TPM_PT) (PT_FIXED + 0)) ++#define TPM_PT_LEVEL ((TPM_PT) (PT_FIXED + 1)) ++#define TPM_PT_REVISION ((TPM_PT) (PT_FIXED + 2)) ++#define TPM_PT_DAY_OF_YEAR ((TPM_PT) (PT_FIXED + 3)) ++#define TPM_PT_YEAR ((TPM_PT) (PT_FIXED + 4)) ++#define TPM_PT_PCR_COUNT ((TPM_PT) (PT_FIXED + 18)) ++ ++/* TPM_SE Constants */ ++typedef grub_uint8_t TPM_SE; ++ ++#define TPM_SE_HMAC ((TPM_SE) 0x00) ++#define TPM_SE_POLICY ((TPM_SE) 0x01) ++#define TPM_SE_TRIAL ((TPM_SE) 0x03) ++ ++/* TPMI_YES_NO Constants */ ++typedef grub_uint8_t TPMI_YES_NO; ++ ++#define TPM_NO ((TPMI_YES_NO)0) ++#define TPM_YES ((TPMI_YES_NO)1) ++ ++/* TPM_ST Constants */ ++typedef grub_uint16_t TPM_ST; ++typedef TPM_ST TPMI_ST_COMMAND_TAG; ++ ++#define TPM_ST_NO_SESSIONS ((TPMI_ST_COMMAND_TAG) 0x8001) ++#define TPM_ST_SESSIONS ((TPMI_ST_COMMAND_TAG) 0x8002) ++ ++/* TPM_HANDLE Types */ ++typedef grub_uint32_t TPM_HANDLE; ++ ++typedef TPM_HANDLE TPMI_RH_HIERARCHY; ++typedef TPM_HANDLE TPMI_RH_LOCKOUT; ++typedef TPM_HANDLE TPMI_SH_AUTH_SESSION; ++typedef TPM_HANDLE TPMI_DH_CONTEXT; ++typedef TPM_HANDLE TPMI_DH_OBJECT; ++typedef TPM_HANDLE TPMI_DH_ENTITY; ++typedef TPM_HANDLE TPMI_SH_POLICY; ++typedef TPM_HANDLE TPMI_DH_PCR; ++typedef TPM_HANDLE TPMI_RH_NV_AUTH; ++typedef TPM_HANDLE TPMI_RH_NV_INDEX; ++ ++/* TPM_RH Constants */ ++typedef TPM_HANDLE TPM_RH; ++ ++#define TPM_RH_FIRST ((TPM_RH) 0x40000000) ++#define TPM_RH_SRK ((TPM_RH) 0x40000000) ++#define TPM_RH_OWNER ((TPM_RH) 0x40000001) ++#define TPM_RH_REVOKE ((TPM_RH) 0x40000002) ++#define TPM_RH_TRANSPORT ((TPM_RH) 0x40000003) ++#define TPM_RH_OPERATOR ((TPM_RH) 0x40000004) ++#define TPM_RH_ADMIN ((TPM_RH) 0x40000005) ++#define TPM_RH_EK ((TPM_RH) 0x40000006) ++#define TPM_RH_NULL ((TPM_RH) 0x40000007) ++#define TPM_RH_UNASSIGNED ((TPM_RH) 0x40000008) ++#define TPM_RS_PW ((TPM_RH) 0x40000009) ++#define TPM_RH_LOCKOUT ((TPM_RH) 0x4000000A) ++#define TPM_RH_ENDORSEMENT ((TPM_RH) 0x4000000B) ++#define TPM_RH_PLATFORM ((TPM_RH) 0x4000000C) ++#define TPM_RH_PLATFORM_NV ((TPM_RH) 0x4000000D) ++#define TPM_RH_AUTH_00 ((TPM_RH) 0x40000010) ++#define TPM_RH_AUTH_FF ((TPM_RH) 0x4000010F) ++#define TPM_RH_LAST ((TPM_RH) 0x4000010F) ++ ++/* TPM2_ECC_CURVE Constants */ ++typedef grub_uint16_t TPM2_ECC_CURVE; ++ ++#define TPM_ECC_NONE ((TPM_ECC_CURVE) 0x0000) ++#define TPM_ECC_NIST_P192 ((TPM_ECC_CURVE) 0x0001) ++#define TPM_ECC_NIST_P224 ((TPM_ECC_CURVE) 0x0002) ++#define TPM_ECC_NIST_P256 ((TPM_ECC_CURVE) 0x0003) ++#define TPM_ECC_NIST_P384 ((TPM_ECC_CURVE) 0x0004) ++#define TPM_ECC_NIST_P521 ((TPM_ECC_CURVE) 0x0005) ++#define TPM_ECC_BN_P256 ((TPM_ECC_CURVE) 0x0010) ++#define TPM_ECC_BN_P638 ((TPM_ECC_CURVE) 0x0011) ++#define TPM_ECC_SM2_P256 ((TPM_ECC_CURVE) 0x0020) ++ ++/* TPM_CC Constants */ ++typedef grub_uint32_t TPM_CC; ++ ++#define TPM_CC_EvictControl ((TPM_CC) 0x00000120) ++#define TPM_CC_CreatePrimary ((TPM_CC) 0x00000131) ++#define TPM_CC_Create ((TPM_CC) 0x00000153) ++#define TPM_CC_FlushContext ((TPM_CC) 0x00000165) ++#define TPM_CC_ReadPublic ((TPM_CC) 0x00000173) ++#define TPM_CC_StartAuthSession ((TPM_CC) 0x00000176) ++#define TPM_CC_PolicyPCR ((TPM_CC) 0x0000017f) ++#define TPM_CC_NV_Read ((TPM_CC) 0x0000014e) ++#define TPM_CC_NV_ReadPublic ((TPM_CC) 0x00000169) ++#define TPM_CC_GetCapability ((TPM_CC) 0x0000017a) ++#define TPM_CC_PCR_Read ((TPM_CC) 0x0000017e) ++#define TPM_CC_Load ((TPM_CC) 0x00000157) ++#define TPM_CC_Unseal ((TPM_CC) 0x0000015e) ++#define TPM_CC_PolicyGetDigest ((TPM_CC) 0x00000189) ++ ++/* Hash algorithm sizes */ ++#define TPM_SHA1_DIGEST_SIZE 20 ++#define TPM_SHA256_DIGEST_SIZE 32 ++#define TPM_SM3_256_DIGEST_SIZE 32 ++#define TPM_SHA384_DIGEST_SIZE 48 ++#define TPM_SHA512_DIGEST_SIZE 64 ++ ++/* Encryption algorithm sizes */ ++#define TPM_MAX_SYM_BLOCK_SIZE 16 ++#define TPM_MAX_SYM_DATA 256 ++#define TPM_MAX_ECC_KEY_BYTES 128 ++#define TPM_MAX_SYM_KEY_BYTES 32 ++#define TPM_MAX_RSA_KEY_BYTES 512 ++ ++/* Buffer Size Constants */ ++#define TPM_MAX_PCRS 32 ++#define TPM_NUM_PCR_BANKS 16 ++#define TPM_PCR_SELECT_MAX ((TPM_MAX_PCRS + 7) / 8) ++#define TPM_MAX_DIGEST_BUFFER 1024 ++#define TPM_MAX_TPM_PROPERTIES 8 ++#define TPM_MAX_NV_BUFFER_SIZE 2048 ++#define TPM_PRIVATE_VENDOR_SPECIFIC_BYTES 1280 ++ ++/* TPM_GENERATED Constants */ ++typedef grub_uint32_t TPM_GENERATED; ++ ++#define TPM_GENERATED_VALUE ((TPM_GENERATED) 0xff544347) ++ ++/* TPM_ALG_ID Types */ ++typedef TPM_ALG_ID TPMI_ALG_PUBLIC; ++typedef TPM_ALG_ID TPMI_ALG_HASH; ++typedef TPM_ALG_ID TPMI_ALG_KEYEDHASH_SCHEME; ++typedef TPM_ALG_ID TPMI_ALG_KDF; ++typedef TPM_ALG_ID TPMI_ALG_SYM_OBJECT; ++typedef TPM_ALG_ID TPMI_ALG_SYM_MODE; ++typedef TPM_ALG_ID TPMI_ALG_RSA_DECRYPT; ++typedef TPM_ALG_ID TPMI_ALG_ECC_SCHEME; ++typedef TPM_ALG_ID TPMI_ALG_ASYM_SCHEME; ++typedef TPM_ALG_ID TPMI_ALG_RSA_SCHEME; ++typedef TPM_ALG_ID TPMI_ALG_SYM; ++ ++/* TPM_KEY_BITS Type */ ++typedef grub_uint16_t TPM_KEY_BITS; ++ ++/* TPM_ECC_CURVE Types */ ++typedef grub_uint16_t TPM_ECC_CURVE; ++ ++typedef TPM_ECC_CURVE TPMI_ECC_CURVE; ++ ++/* TPMI_RH_PROVISION Type */ ++typedef TPM_HANDLE TPMI_RH_PROVISION; ++ ++/* TPMI_RH_PROVISION Type */ ++typedef TPM_HANDLE TPMI_DH_PERSISTENT; ++ ++#endif /* ! GRUB_TPM2_INTERNAL_TYPES_HEADER */ +diff --git a/include/grub/tpm2/mu.h b/include/grub/tpm2/mu.h +new file mode 100644 +index 0000000000..4f4058f9d6 +--- /dev/null ++++ b/include/grub/tpm2/mu.h +@@ -0,0 +1,292 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2022 Microsoft Corporation ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#ifndef GRUB_TPM2_MU_HEADER ++#define GRUB_TPM2_MU_HEADER 1 ++ ++#include ++#include ++ ++void ++grub_tpm2_mu_TPMS_AUTH_COMMAND_Marshal (grub_tpm2_buffer_t buf, ++ const TPMS_AUTH_COMMAND* authCommand); ++ ++void ++grub_tpm2_mu_TPM2B_Marshal (grub_tpm2_buffer_t buf, ++ grub_uint16_t size, ++ const grub_uint8_t* buffer); ++ ++void ++grub_tpm2_mu_TPMU_SYM_KEY_BITS_Marshal (grub_tpm2_buffer_t buf, ++ TPMI_ALG_SYM_OBJECT algorithm, ++ TPMU_SYM_KEY_BITS *p); ++ ++void ++grub_tpm2_mu_TPMU_SYM_MODE_Marshal (grub_tpm2_buffer_t buf, ++ TPMI_ALG_SYM_OBJECT algorithm, ++ TPMU_SYM_MODE *p); ++ ++void ++grub_tpm2_mu_TPMT_SYM_DEF_Marshal (grub_tpm2_buffer_t buf, ++ TPMT_SYM_DEF *p); ++ ++void ++grub_tpm2_mu_TPMS_PCR_SELECTION_Marshal (grub_tpm2_buffer_t buf, ++ const TPMS_PCR_SELECTION* pcrSelection); ++ ++void ++grub_tpm2_mu_TPML_PCR_SELECTION_Marshal (grub_tpm2_buffer_t buf, ++ const TPML_PCR_SELECTION* pcrSelection); ++ ++void ++grub_tpm2_mu_TPMA_OBJECT_Marshal (grub_tpm2_buffer_t buf, ++ const TPMA_OBJECT *p); ++ ++void ++grub_tpm2_mu_TPMS_SCHEME_XOR_Marshal (grub_tpm2_buffer_t buf, ++ TPMS_SCHEME_XOR *p); ++ ++void ++grub_tpm2_mu_TPMS_SCHEME_HMAC_Marshal (grub_tpm2_buffer_t buf, ++ TPMS_SCHEME_HMAC *p); ++ ++void ++grub_tpm2_mu_TPMU_SCHEME_KEYEDHASH_Marshal (grub_tpm2_buffer_t buf, ++ TPMI_ALG_KEYEDHASH_SCHEME scheme, ++ TPMU_SCHEME_KEYEDHASH *p); ++ ++void ++grub_tpm2_mu_TPMT_KEYEDHASH_SCHEME_Marshal (grub_tpm2_buffer_t buf, ++ TPMT_KEYEDHASH_SCHEME *p); ++ ++void ++grub_tpm2_mu_TPMS_KEYEDHASH_PARMS_Marshal (grub_tpm2_buffer_t buf, ++ TPMS_KEYEDHASH_PARMS *p); ++ ++void ++grub_tpm2_mu_TPMT_SYM_DEF_OBJECT_Marshal (grub_tpm2_buffer_t buf, ++ TPMT_SYM_DEF_OBJECT *p); ++ ++void ++grub_tpm2_mu_TPMU_ASYM_SCHEME_Marshal (grub_tpm2_buffer_t buf, ++ TPMI_ALG_RSA_DECRYPT scheme, ++ TPMU_ASYM_SCHEME *p); ++ ++void ++grub_tpm2_mu_TPMT_RSA_SCHEME_Marshal (grub_tpm2_buffer_t buf, ++ TPMT_RSA_SCHEME *p); ++ ++void ++grub_tpm2_mu_TPMS_RSA_PARMS_Marshal (grub_tpm2_buffer_t buf, ++ TPMS_RSA_PARMS *p); ++ ++void ++grub_tpm2_mu_TPMS_SYMCIPHER_PARMS_Marshal (grub_tpm2_buffer_t buf, ++ TPMS_SYMCIPHER_PARMS *p); ++ ++void ++grub_tpm2_mu_TPMT_ECC_SCHEME_Marshal (grub_tpm2_buffer_t buf, ++ TPMT_ECC_SCHEME *p); ++ ++void ++grub_tpm2_mu_TPMU_KDF_SCHEME_Marshal (grub_tpm2_buffer_t buf, ++ TPMI_ALG_KDF scheme, ++ TPMU_KDF_SCHEME *p); ++ ++void ++grub_tpm2_mu_TPMT_KDF_SCHEME_Marshal (grub_tpm2_buffer_t buf, ++ TPMT_KDF_SCHEME *p); ++ ++void ++grub_tpm2_mu_TPMS_ECC_PARMS_Marshal (grub_tpm2_buffer_t buf, ++ TPMS_ECC_PARMS *p); ++ ++void ++grub_tpm2_mu_TPMU_PUBLIC_PARMS_Marshal (grub_tpm2_buffer_t buf, ++ grub_uint32_t type, ++ TPMU_PUBLIC_PARMS *p); ++ ++void ++grub_tpm2_mu_TPMS_ECC_POINT_Marshal (grub_tpm2_buffer_t buf, ++ TPMS_ECC_POINT *p); ++ ++void ++grub_tpm2_mu_TPMU_PUBLIC_ID_Marshal (grub_tpm2_buffer_t buf, ++ TPMI_ALG_PUBLIC type, ++ TPMU_PUBLIC_ID *p); ++ ++void ++grub_tpm2_mu_TPMT_PUBLIC_Marshal (grub_tpm2_buffer_t buf, ++ TPMT_PUBLIC *p); ++ ++void ++grub_tpm2_mu_TPM2B_PUBLIC_Marshal (grub_tpm2_buffer_t buf, ++ TPM2B_PUBLIC *p); ++ ++void ++grub_tpm2_mu_TPMS_SENSITIVE_CREATE_Marshal (grub_tpm2_buffer_t buf, ++ TPMS_SENSITIVE_CREATE *p); ++ ++void ++grub_tpm2_mu_TPM2B_SENSITIVE_CREATE_Marshal (grub_tpm2_buffer_t buf, ++ TPM2B_SENSITIVE_CREATE *sensitiveCreate); ++ ++void ++grub_tpm2_mu_TPM2B_Unmarshal (grub_tpm2_buffer_t buf, ++ TPM2B* p); ++ ++void ++grub_tpm2_mu_TPMS_AUTH_RESPONSE_Unmarshal (grub_tpm2_buffer_t buf, ++ TPMS_AUTH_RESPONSE* p); ++ ++void ++grub_tpm2_mu_TPM2B_DIGEST_Unmarshal (grub_tpm2_buffer_t buf, ++ TPM2B_DIGEST* digest); ++ ++void ++grub_tpm2_mu_TPMA_OBJECT_Unmarshal (grub_tpm2_buffer_t buf, ++ TPMA_OBJECT *p); ++ ++void ++grub_tpm2_mu_TPMS_SCHEME_HMAC_Unmarshal (grub_tpm2_buffer_t buf, ++ TPMS_SCHEME_HMAC *p); ++ ++void ++grub_tpm2_mu_TPMS_SCHEME_XOR_Unmarshal (grub_tpm2_buffer_t buf, ++ TPMS_SCHEME_XOR *p); ++ ++void ++grub_tpm2_mu_TPMU_SCHEME_KEYEDHASH_Unmarshal (grub_tpm2_buffer_t buf, ++ TPMI_ALG_KEYEDHASH_SCHEME scheme, ++ TPMU_SCHEME_KEYEDHASH *p); ++ ++void ++grub_tpm2_mu_TPMT_KEYEDHASH_SCHEME_Unmarshal (grub_tpm2_buffer_t buf, ++ TPMT_KEYEDHASH_SCHEME *p); ++ ++void ++grub_tpm2_mu_TPMS_KEYEDHASH_PARMS_Unmarshal (grub_tpm2_buffer_t buf, ++ TPMS_KEYEDHASH_PARMS *p); ++ ++void ++grub_tpm2_mu_TPMU_SYM_KEY_BITS_Unmarshal (grub_tpm2_buffer_t buf, ++ TPMI_ALG_SYM_OBJECT algorithm, ++ TPMU_SYM_KEY_BITS *p); ++ ++void ++grub_tpm2_mu_TPMU_SYM_MODE_Unmarshal (grub_tpm2_buffer_t buf, ++ TPMI_ALG_SYM_OBJECT algorithm, ++ TPMU_SYM_MODE *p); ++ ++void ++grub_tpm2_mu_TPMT_SYM_DEF_OBJECT_Unmarshal (grub_tpm2_buffer_t buf, ++ TPMT_SYM_DEF_OBJECT *p); ++ ++void ++grub_tpm2_mu_TPMS_SYMCIPHER_PARMS_Unmarshal (grub_tpm2_buffer_t buf, ++ TPMS_SYMCIPHER_PARMS *p); ++ ++void ++grub_tpm2_mu_TPMU_ASYM_SCHEME_Unmarshal (grub_tpm2_buffer_t buf, ++ TPMI_ALG_RSA_DECRYPT scheme, ++ TPMU_ASYM_SCHEME *p); ++ ++void ++grub_tpm2_mu_TPMT_RSA_SCHEME_Unmarshal (grub_tpm2_buffer_t buf, ++ TPMT_RSA_SCHEME *p); ++ ++void ++grub_tpm2_mu_TPMS_RSA_PARMS_Unmarshal (grub_tpm2_buffer_t buf, ++ TPMS_RSA_PARMS *p); ++ ++void ++grub_tpm2_mu_TPMT_ECC_SCHEME_Unmarshal (grub_tpm2_buffer_t buf, ++ TPMT_ECC_SCHEME *p); ++ ++void ++grub_tpm2_mu_TPMU_KDF_SCHEME_Unmarshal (grub_tpm2_buffer_t buf, ++ TPMI_ALG_KDF scheme, ++ TPMU_KDF_SCHEME *p); ++ ++void ++grub_tpm2_mu_TPMT_KDF_SCHEME_Unmarshal (grub_tpm2_buffer_t buf, ++ TPMT_KDF_SCHEME *p); ++ ++void ++grub_tpm2_mu_TPMS_ECC_PARMS_Unmarshal (grub_tpm2_buffer_t buf, ++ TPMS_ECC_PARMS *p); ++ ++void ++grub_tpm2_mu_TPMU_PUBLIC_PARMS_Unmarshal (grub_tpm2_buffer_t buf, ++ grub_uint32_t type, ++ TPMU_PUBLIC_PARMS *p); ++ ++void ++grub_tpm2_mu_TPMS_ECC_POINT_Unmarshal (grub_tpm2_buffer_t buf, ++ TPMS_ECC_POINT *p); ++ ++void ++grub_tpm2_mu_TPMU_PUBLIC_ID_Unmarshal (grub_tpm2_buffer_t buf, ++ TPMI_ALG_PUBLIC type, ++ TPMU_PUBLIC_ID *p); ++ ++void ++grub_tpm2_mu_TPMT_PUBLIC_Unmarshal (grub_tpm2_buffer_t buf, ++ TPMT_PUBLIC *p); ++ ++void ++grub_tpm2_mu_TPM2B_PUBLIC_Unmarshal (grub_tpm2_buffer_t buf, ++ TPM2B_PUBLIC *p); ++ ++void ++grub_tpm2_mu_TPMS_NV_PUBLIC_Unmarshal (grub_tpm2_buffer_t buf, ++ TPMS_NV_PUBLIC *p); ++ ++void ++grub_tpm2_mu_TPM2B_NV_PUBLIC_Unmarshal (grub_tpm2_buffer_t buf, ++ TPM2B_NV_PUBLIC *p); ++ ++void ++grub_tpm2_mu_TPM2B_NAME_Unmarshal (grub_tpm2_buffer_t buf, ++ TPM2B_NAME *n); ++ ++void ++grub_tpm2_mu_TPMS_TAGGED_PROPERTY_Unmarshal (grub_tpm2_buffer_t buf, ++ TPMS_TAGGED_PROPERTY* property); ++ ++void ++grub_tpm2_mu_TPMS_CAPABILITY_DATA_tpmProperties_Unmarshal (grub_tpm2_buffer_t buf, ++ TPMS_CAPABILITY_DATA* capabilityData); ++ ++void ++grub_tpm2_mu_TPMT_TK_CREATION_Unmarshal (grub_tpm2_buffer_t buf, ++ TPMT_TK_CREATION *p); ++ ++void ++grub_tpm2_mu_TPMS_PCR_SELECTION_Unmarshal (grub_tpm2_buffer_t buf, ++ TPMS_PCR_SELECTION* pcrSelection); ++ ++void ++grub_tpm2_mu_TPML_PCR_SELECTION_Unmarshal (grub_tpm2_buffer_t buf, ++ TPML_PCR_SELECTION* pcrSelection); ++ ++void ++grub_tpm2_mu_TPML_DIGEST_Unmarshal (grub_tpm2_buffer_t buf, ++ TPML_DIGEST* digest); ++ ++#endif /* ! GRUB_TPM2_MU_HEADER */ +diff --git a/include/grub/tpm2/tcg2.h b/include/grub/tpm2/tcg2.h +new file mode 100644 +index 0000000000..99f2fdd3b9 +--- /dev/null ++++ b/include/grub/tpm2/tcg2.h +@@ -0,0 +1,34 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2022 Microsoft Corporation ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#ifndef GRUB_TPM2_TCG2_HEADER ++#define GRUB_TPM2_TCG2_HEADER 1 ++ ++#include ++#include ++ ++grub_err_t ++grub_tcg2_get_max_output_size (grub_size_t *size); ++ ++grub_err_t ++grub_tcg2_submit_command (grub_size_t input_size, ++ grub_uint8_t *input, ++ grub_size_t output_size, ++ grub_uint8_t *output); ++ ++#endif /* ! GRUB_TPM2_TCG2_HEADER */ +diff --git a/include/grub/tpm2/tpm2.h b/include/grub/tpm2/tpm2.h +new file mode 100644 +index 0000000000..4b7a9fbb57 +--- /dev/null ++++ b/include/grub/tpm2/tpm2.h +@@ -0,0 +1,38 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2022 Microsoft Corporation ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#ifndef GRUB_TPM2_TPM2_HEADER ++#define GRUB_TPM2_TPM2_HEADER 1 ++ ++#include ++#include ++#include ++ ++/* Defined in: TCG TPM Specification, v1.59, Part 2, Section 10.6.1. */ ++#define TPM2_PCR_TO_SELECT(x) ((x) / 8) ++#define TPM2_PCR_TO_BIT(x) (1 << ((x) % 8)) ++ ++/* Well-Known Windows SRK handle */ ++#define TPM2_SRK_HANDLE 0x81000001 ++ ++typedef struct TPM2_SEALED_KEY { ++ TPM2B_PUBLIC public; ++ TPM2B_PRIVATE private; ++} TPM2_SEALED_KEY; ++ ++#endif /* ! GRUB_TPM2_TPM2_HEADER */ +-- +2.34.1 + diff --git a/0012-protectors-Add-TPM2-Key-Protector.patch b/0012-protectors-Add-TPM2-Key-Protector.patch new file mode 100644 index 0000000..e18bc68 --- /dev/null +++ b/0012-protectors-Add-TPM2-Key-Protector.patch @@ -0,0 +1,977 @@ +From b173db7537920ee5706e1c961fea3086ada6b6dd Mon Sep 17 00:00:00 2001 +From: Hernan Gatta +Date: Tue, 1 Feb 2022 05:02:55 -0800 +Subject: [PATCH 12/14] protectors: Add TPM2 Key Protector + +The TPM2 key protector is a module that enables the automatic retrieval of a +fully-encrypted disk's unlocking key from a TPM 2.0. + +The theory of operation is such that the module accepts various arguments, most +of which are optional and therefore possess reasonable defaults. One of these +arguments is the keyfile parameter, which is mandatory. + +The value of this parameter must be a path to a sealed key file (e.g., +(hd0,gpt1)/boot/grub2/sealed_key). This sealed key file is created via the +grub-protect tool. The tool utilizes the TPM's sealing functionality to seal +(i.e., encrypt) an unlocking key using a Storage Root Key (SRK) to the values of +various Platform Configuration Registers (PCRs). These PCRs reflect the state of +the system as it boots. If the values are as expected, the system may be +considered trustworthy, at which point the TPM allows for a caller to utilize +the private component of the SRK to unseal (i.e., decrypt) the sealed key file. +The caller, in this case, is this key protector. + +The TPM2 key protector registers two commands: + +- tpm2_key_protector_init: Initializes the state of the TPM2 key protector for + later usage, clearing any previous state, too, if + any. + +- tpm2_key_protector_clear: Clears any state set by tpm2_key_protector_init. + +The way this is expected to be used requires the user to, either interactively +or, normally, via a boot script, initialize (i.e., configure) the key protector +and then specify that it be used by the cryptomount command (modifications to +this command are in a different patch). + +For instance: + +tpm2_key_protector_init --keyfile=KEYFILE1 +cryptomount DISK1 -k tpm2 + +tpm2_key_protector_init --keyfile=KEYFILE2 --pcrs=7,11 +cryptomount DISK2 -k tpm2 + +If a user does not initialize the key protector and attempts to use it anyway, +the protector returns an error. + +Signed-off-by: Hernan Gatta +--- + grub-core/Makefile.core.def | 10 + + grub-core/tpm2/args.c | 129 ++++++ + grub-core/tpm2/module.c | 710 ++++++++++++++++++++++++++++++ + include/grub/tpm2/internal/args.h | 39 ++ + 4 files changed, 888 insertions(+) + create mode 100644 grub-core/tpm2/args.c + create mode 100644 grub-core/tpm2/module.c + create mode 100644 include/grub/tpm2/internal/args.h + +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index b0001a33cf..850cee2b13 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -2561,6 +2561,16 @@ module = { + enable = efi; + }; + ++module = { ++ name = tpm2; ++ common = tpm2/args.c; ++ common = tpm2/buffer.c; ++ common = tpm2/module.c; ++ common = tpm2/mu.c; ++ common = tpm2/tpm2.c; ++ efi = tpm2/tcg2.c; ++}; ++ + module = { + name = tr; + common = commands/tr.c; +diff --git a/grub-core/tpm2/args.c b/grub-core/tpm2/args.c +new file mode 100644 +index 0000000000..90c7cd8991 +--- /dev/null ++++ b/grub-core/tpm2/args.c +@@ -0,0 +1,129 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2022 Microsoft Corporation ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++#include ++#include ++#include ++ ++grub_err_t ++grub_tpm2_protector_parse_pcrs (char *value, grub_uint8_t *pcrs, ++ grub_uint8_t *pcr_count) ++{ ++ char *current_pcr = value; ++ char *next_pcr; ++ unsigned long pcr; ++ grub_uint8_t i; ++ ++ if (grub_strlen (value) == 0) ++ return GRUB_ERR_BAD_ARGUMENT; ++ ++ *pcr_count = 0; ++ for (i = 0; i < TPM_MAX_PCRS; i++) ++ { ++ next_pcr = grub_strchr (current_pcr, ','); ++ if (next_pcr == current_pcr) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("Empty entry in PCR list")); ++ if (next_pcr) ++ *next_pcr = '\0'; ++ ++ grub_errno = GRUB_ERR_NONE; ++ pcr = grub_strtoul (current_pcr, NULL, 10); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_error (grub_errno, ++ N_("Entry '%s' in PCR list is not a number"), ++ current_pcr); ++ ++ if (pcr > TPM_MAX_PCRS) ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, ++ N_("Entry %lu in PCR list is too large to be a PCR " ++ "number, PCR numbers range from 0 to %u"), ++ pcr, TPM_MAX_PCRS); ++ ++ pcrs[i] = (grub_uint8_t)pcr; ++ *pcr_count += 1; ++ ++ if (!next_pcr) ++ break; ++ ++ current_pcr = next_pcr + 1; ++ if (*current_pcr == '\0') ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("Trailing comma at the end of PCR list")); ++ } ++ ++ if (i == TPM_MAX_PCRS) ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, ++ N_("Too many PCRs in PCR list, the maximum number of " ++ "PCRs is %u"), TPM_MAX_PCRS); ++ ++ return GRUB_ERR_NONE; ++} ++ ++grub_err_t ++grub_tpm2_protector_parse_asymmetric (const char *value, TPM_ALG_ID *asymmetric) ++{ ++ if (grub_strcasecmp (value, "ECC") == 0) ++ *asymmetric = TPM_ALG_ECC; ++ else if (grub_strcasecmp (value, "RSA") == 0) ++ *asymmetric = TPM_ALG_RSA; ++ else ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, ++ N_("Value '%s' is not a valid asymmetric key type"), ++ value); ++ ++ return GRUB_ERR_NONE; ++} ++ ++grub_err_t ++grub_tpm2_protector_parse_bank (const char *value, TPM_ALG_ID *bank) ++{ ++ if (grub_strcasecmp (value, "SHA1") == 0) ++ *bank = TPM_ALG_SHA1; ++ else if (grub_strcasecmp (value, "SHA256") == 0) ++ *bank = TPM_ALG_SHA256; ++ else if (grub_strcasecmp (value, "SHA384") == 0) ++ *bank = TPM_ALG_SHA384; ++ else ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, ++ N_("Value '%s' is not a valid PCR bank"), value); ++ ++ return GRUB_ERR_NONE; ++} ++ ++grub_err_t ++grub_tpm2_protector_parse_tpm_handle (const char *value, TPM_HANDLE *handle) ++{ ++ unsigned long num; ++ ++ grub_errno = GRUB_ERR_NONE; ++ num = grub_strtoul (value, NULL, 0); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_error (grub_errno, N_("TPM handle value '%s' is not a number"), ++ value); ++ ++ if (num > GRUB_UINT_MAX) ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, ++ N_("Value %lu is too large to be a TPM handle, TPM " ++ "handles are unsigned 32-bit integers"), num); ++ ++ *handle = (TPM_HANDLE)num; ++ ++ return GRUB_ERR_NONE; ++} +diff --git a/grub-core/tpm2/module.c b/grub-core/tpm2/module.c +new file mode 100644 +index 0000000000..3f2f386f7e +--- /dev/null ++++ b/grub-core/tpm2/module.c +@@ -0,0 +1,710 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2022 Microsoft Corporation ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++GRUB_MOD_LICENSE ("GPLv3+"); ++ ++typedef enum grub_tpm2_protector_mode ++{ ++ GRUB_TPM2_PROTECTOR_MODE_UNSET, ++ GRUB_TPM2_PROTECTOR_MODE_SRK, ++ GRUB_TPM2_PROTECTOR_MODE_NV ++} grub_tpm2_protector_mode_t; ++ ++struct grub_tpm2_protector_context ++{ ++ grub_tpm2_protector_mode_t mode; ++ grub_uint8_t pcrs[TPM_MAX_PCRS]; ++ grub_uint8_t pcr_count; ++ TPM_ALG_ID asymmetric; ++ TPM_ALG_ID bank; ++ const char *keyfile; ++ TPM_HANDLE srk; ++ TPM_HANDLE nv; ++}; ++ ++static const struct grub_arg_option grub_tpm2_protector_init_cmd_options[] = ++ { ++ /* Options for all modes */ ++ { ++ .longarg = "mode", ++ .shortarg = 'm', ++ .flags = 0, ++ .arg = NULL, ++ .type = ARG_TYPE_STRING, ++ .doc = ++ N_("Unseal key using SRK ('srk') (default) or retrieve it from an NV " ++ "Index ('nv')."), ++ }, ++ { ++ .longarg = "pcrs", ++ .shortarg = 'p', ++ .flags = 0, ++ .arg = NULL, ++ .type = ARG_TYPE_STRING, ++ .doc = ++ N_("Comma-separated list of PCRs used to authorize key release " ++ "(e.g., '7,11', default is 7."), ++ }, ++ { ++ .longarg = "bank", ++ .shortarg = 'b', ++ .flags = 0, ++ .arg = NULL, ++ .type = ARG_TYPE_STRING, ++ .doc = ++ N_("Bank of PCRs used to authorize key release: " ++ "SHA1, SHA256 (default), or SHA384."), ++ }, ++ /* SRK-mode options */ ++ { ++ .longarg = "keyfile", ++ .shortarg = 'k', ++ .flags = 0, ++ .arg = NULL, ++ .type = ARG_TYPE_STRING, ++ .doc = ++ N_("Required in SRK mode, path to the sealed key file to unseal using " ++ "the TPM (e.g., (hd0,gpt1)/boot/grub2/sealed_key)."), ++ }, ++ { ++ .longarg = "srk", ++ .shortarg = 's', ++ .flags = 0, ++ .arg = NULL, ++ .type = ARG_TYPE_STRING, ++ .doc = ++ N_("In SRK mode, the SRK handle if the SRK is persistent " ++ "(default is 0x81000001)."), ++ }, ++ { ++ .longarg = "asymmetric", ++ .shortarg = 'a', ++ .flags = 0, ++ .arg = NULL, ++ .type = ARG_TYPE_STRING, ++ .doc = ++ N_("In SRK mode, the type of SRK: RSA (default) or ECC."), ++ }, ++ /* NV Index-mode options */ ++ { ++ .longarg = "nvindex", ++ .shortarg = 'n', ++ .flags = 0, ++ .arg = NULL, ++ .type = ARG_TYPE_STRING, ++ .doc = ++ N_("Required in NV Index mode, the NV handle to read which must " ++ "readily exist on the TPM and which contains the key."), ++ }, ++ /* End of list */ ++ {0, 0, 0, 0, 0, 0} ++ }; ++ ++static grub_extcmd_t grub_tpm2_protector_init_cmd; ++static grub_extcmd_t grub_tpm2_protector_clear_cmd; ++static struct grub_tpm2_protector_context grub_tpm2_protector_ctx = { 0 }; ++ ++static grub_err_t ++grub_tpm2_protector_srk_read_keyfile (const char *filepath, void **buffer, ++ grub_size_t *buffer_size) ++{ ++ grub_file_t sealed_key_file; ++ grub_off_t sealed_key_size; ++ void *sealed_key_buffer; ++ grub_off_t sealed_key_read; ++ ++ sealed_key_file = grub_file_open (filepath, GRUB_FILE_TYPE_NONE); ++ if (!sealed_key_file) ++ { ++ grub_dprintf ("tpm2", "Could not open sealed key file.\n"); ++ /* grub_file_open sets grub_errno on error, and if we do no unset it, ++ * future calls to grub_file_open will fail (and so will anybody up the ++ * stack who checks the value, if any). */ ++ grub_errno = GRUB_ERR_NONE; ++ return GRUB_ERR_FILE_NOT_FOUND; ++ } ++ ++ sealed_key_size = grub_file_size (sealed_key_file); ++ if (!sealed_key_size) ++ { ++ grub_dprintf ("tpm2", "Could not read sealed key file size.\n"); ++ grub_file_close (sealed_key_file); ++ return GRUB_ERR_OUT_OF_RANGE; ++ } ++ ++ sealed_key_buffer = grub_malloc (sealed_key_size); ++ if (!sealed_key_buffer) ++ { ++ grub_dprintf ("tpm2", "Could not allocate buffer for sealed key.\n"); ++ grub_file_close (sealed_key_file); ++ return GRUB_ERR_OUT_OF_MEMORY; ++ } ++ ++ sealed_key_read = grub_file_read (sealed_key_file, sealed_key_buffer, ++ sealed_key_size); ++ if (sealed_key_read != sealed_key_size) ++ { ++ grub_dprintf ("tpm2", "Could not retrieve sealed key file contents.\n"); ++ grub_free (sealed_key_buffer); ++ grub_file_close (sealed_key_file); ++ return GRUB_ERR_FILE_READ_ERROR; ++ } ++ ++ grub_file_close (sealed_key_file); ++ ++ *buffer = sealed_key_buffer; ++ *buffer_size = sealed_key_size; ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_tpm2_protector_srk_unmarshal_keyfile (void *sealed_key, ++ grub_size_t sealed_key_size, ++ TPM2_SEALED_KEY *sk) ++{ ++ struct grub_tpm2_buffer buf; ++ ++ grub_tpm2_buffer_init (&buf); ++ if (sealed_key_size > buf.cap) ++ { ++ grub_dprintf ("tpm2", "Sealed key file is larger than decode buffer " ++ "(%lu vs %lu bytes).\n", sealed_key_size, buf.cap); ++ return GRUB_ERR_BAD_ARGUMENT; ++ } ++ ++ grub_memcpy (buf.data, sealed_key, sealed_key_size); ++ buf.size = sealed_key_size; ++ ++ grub_tpm2_mu_TPM2B_PUBLIC_Unmarshal (&buf, &sk->public); ++ grub_tpm2_mu_TPM2B_Unmarshal (&buf, (TPM2B *)&sk->private); ++ ++ if (buf.error) ++ { ++ grub_dprintf ("tpm2", "Could not unmarshal sealed key file, it is likely " ++ "malformed.\n"); ++ return GRUB_ERR_BAD_ARGUMENT; ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_tpm2_protector_srk_get (const struct grub_tpm2_protector_context *ctx, ++ TPM_HANDLE *srk) ++{ ++ TPM_RC rc; ++ TPM2B_PUBLIC public; ++ TPMS_AUTH_COMMAND authCommand = { 0 }; ++ TPM2B_SENSITIVE_CREATE inSensitive = { 0 }; ++ TPM2B_PUBLIC inPublic = { 0 }; ++ TPM2B_DATA outsideInfo = { 0 }; ++ TPML_PCR_SELECTION creationPcr = { 0 }; ++ TPM2B_PUBLIC outPublic = { 0 }; ++ TPM2B_CREATION_DATA creationData = { 0 }; ++ TPM2B_DIGEST creationHash = { 0 }; ++ TPMT_TK_CREATION creationTicket = { 0 }; ++ TPM2B_NAME srkName = { 0 }; ++ TPM_HANDLE srkHandle; ++ ++ /* Find SRK */ ++ rc = TPM2_ReadPublic (ctx->srk, NULL, &public); ++ if (rc == TPM_RC_SUCCESS) ++ { ++ *srk = ctx->srk; ++ return GRUB_ERR_NONE; ++ } ++ ++ /* The handle exists but its public area could not be read. */ ++ if ((rc & ~TPM_RC_N_MASK) != TPM_RC_HANDLE) ++ { ++ grub_dprintf ("tpm2", "The SRK handle (0x%x) exists on the TPM but its " ++ "public area could not be read (TPM2_ReadPublic " ++ "failed with TSS/TPM error %u).\n", ctx->srk, rc); ++ return GRUB_ERR_BAD_DEVICE; ++ } ++ ++ /* Create SRK */ ++ authCommand.sessionHandle = TPM_RS_PW; ++ inPublic.publicArea.type = ctx->asymmetric; ++ inPublic.publicArea.nameAlg = TPM_ALG_SHA256; ++ inPublic.publicArea.objectAttributes.restricted = 1; ++ inPublic.publicArea.objectAttributes.userWithAuth = 1; ++ inPublic.publicArea.objectAttributes.decrypt = 1; ++ inPublic.publicArea.objectAttributes.fixedTPM = 1; ++ inPublic.publicArea.objectAttributes.fixedParent = 1; ++ inPublic.publicArea.objectAttributes.sensitiveDataOrigin = 1; ++ inPublic.publicArea.objectAttributes.noDA = 1; ++ ++ if (ctx->asymmetric == TPM_ALG_RSA) ++ { ++ inPublic.publicArea.parameters.rsaDetail.symmetric.algorithm = TPM_ALG_AES; ++ inPublic.publicArea.parameters.rsaDetail.symmetric.keyBits.aes = 128; ++ inPublic.publicArea.parameters.rsaDetail.symmetric.mode.aes = TPM_ALG_CFB; ++ inPublic.publicArea.parameters.rsaDetail.scheme.scheme = TPM_ALG_NULL; ++ inPublic.publicArea.parameters.rsaDetail.keyBits = 2048; ++ inPublic.publicArea.parameters.rsaDetail.exponent = 0; ++ } ++ else if (ctx->asymmetric == TPM_ALG_ECC) ++ { ++ inPublic.publicArea.parameters.eccDetail.symmetric.algorithm = TPM_ALG_AES; ++ inPublic.publicArea.parameters.eccDetail.symmetric.keyBits.aes = 128; ++ inPublic.publicArea.parameters.eccDetail.symmetric.mode.aes = TPM_ALG_CFB; ++ inPublic.publicArea.parameters.eccDetail.scheme.scheme = TPM_ALG_NULL; ++ inPublic.publicArea.parameters.eccDetail.curveID = TPM_ECC_NIST_P256; ++ inPublic.publicArea.parameters.eccDetail.kdf.scheme = TPM_ALG_NULL; ++ } ++ else ++ return GRUB_ERR_BAD_ARGUMENT; ++ ++ rc = TPM2_CreatePrimary (TPM_RH_OWNER, &authCommand, &inSensitive, &inPublic, ++ &outsideInfo, &creationPcr, &srkHandle, &outPublic, ++ &creationData, &creationHash, &creationTicket, ++ &srkName, NULL); ++ if (rc != TPM_RC_SUCCESS) ++ { ++ grub_dprintf ("tpm2", "Could not create SRK (TPM2_CreatePrimary failed " ++ "with TSS/TPM error %u).\n", rc); ++ return GRUB_ERR_BAD_DEVICE; ++ } ++ ++ *srk = srkHandle; ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_tpm2_protector_srk_recover (const struct grub_tpm2_protector_context *ctx, ++ grub_uint8_t **key, grub_size_t *key_size) ++{ ++ TPM_RC rc; ++ TPM2_SEALED_KEY sealed_key; ++ void *sealed_key_bytes; ++ grub_size_t sealed_key_size; ++ TPM_HANDLE srk_handle; ++ TPM2B_NONCE nonceCaller = { 0 }; ++ TPM2B_ENCRYPTED_SECRET salt = { 0 }; ++ TPMT_SYM_DEF symmetric = { 0 }; ++ TPM2B_NONCE nonceTPM = { 0 }; ++ TPMI_SH_AUTH_SESSION session; ++ TPML_PCR_SELECTION pcrSel = { ++ .count = 1, ++ .pcrSelections = { ++ { ++ .hash = ctx->bank, ++ .sizeOfSelect = 3, ++ .pcrSelect = { 0 } ++ }, ++ } ++ }; ++ TPMS_AUTH_COMMAND authCmd = { 0 }; ++ TPM_HANDLE sealed_key_handle; ++ TPM2B_NAME name; ++ TPMS_AUTH_RESPONSE authResponse; ++ TPM2B_SENSITIVE_DATA data; ++ grub_uint8_t *key_out; ++ grub_uint8_t i; ++ grub_err_t err; ++ ++ /* Retrieve Sealed Key */ ++ err = grub_tpm2_protector_srk_read_keyfile (ctx->keyfile, &sealed_key_bytes, ++ &sealed_key_size); ++ if (err) ++ return grub_error (err, N_("Failed to read key file %s"), ctx->keyfile); ++ ++ err = grub_tpm2_protector_srk_unmarshal_keyfile (sealed_key_bytes, ++ sealed_key_size, ++ &sealed_key); ++ if (err) ++ { ++ grub_error (err, N_("Failed to unmarshal key, ensure the key file is in " ++ "TPM wire format")); ++ goto exit1; ++ } ++ ++ /* Get SRK */ ++ err = grub_tpm2_protector_srk_get (ctx, &srk_handle); ++ if (err) ++ { ++ grub_error (err, N_("Failed to retrieve the SRK")); ++ goto exit1; ++ } ++ ++ err = GRUB_ERR_BAD_DEVICE; ++ ++ /* Start Auth Session */ ++ nonceCaller.size = TPM_SHA256_DIGEST_SIZE; ++ symmetric.algorithm = TPM_ALG_NULL; ++ ++ rc = TPM2_StartAuthSession (TPM_RH_NULL, TPM_RH_NULL, 0, &nonceCaller, &salt, ++ TPM_SE_POLICY, &symmetric, TPM_ALG_SHA256, ++ &session, &nonceTPM, 0); ++ if (rc) ++ { ++ grub_error (err, N_("Failed to start auth session (TPM2_StartAuthSession " ++ "failed with TSS/TPM error %u)"), rc); ++ goto exit2; ++ } ++ ++ /* Policy PCR */ ++ for (i = 0; i < ctx->pcr_count; i++) ++ pcrSel ++ .pcrSelections[0] ++ .pcrSelect[TPM2_PCR_TO_SELECT(ctx->pcrs[i])] ++ |= TPM2_PCR_TO_BIT(ctx->pcrs[i]); ++ ++ rc = TPM2_PolicyPCR (session, NULL, NULL, &pcrSel, NULL); ++ if (rc) ++ { ++ grub_error (err, N_("Failed to submit PCR policy (TPM2_PolicyPCR failed " ++ "with TSS/TPM error %u)"), rc); ++ goto exit3; ++ } ++ ++ /* Load Sealed Key */ ++ authCmd.sessionHandle = TPM_RS_PW; ++ rc = TPM2_Load (srk_handle, &authCmd, &sealed_key.private, &sealed_key.public, ++ &sealed_key_handle, &name, &authResponse); ++ if (rc) ++ { ++ grub_error (err, N_("Failed to load sealed key (TPM2_Load failed with " ++ "TSS/TPM error %u)"), rc); ++ goto exit3; ++ } ++ ++ /* Unseal Sealed Key */ ++ authCmd.sessionHandle = session; ++ grub_memset (&authResponse, 0, sizeof (authResponse)); ++ ++ rc = TPM2_Unseal (sealed_key_handle, &authCmd, &data, &authResponse); ++ if (rc) ++ { ++ grub_error (err, N_("Failed to unseal sealed key (TPM2_Unseal failed " ++ "with TSS/TPM error %u)"), rc); ++ goto exit4; ++ } ++ ++ /* Epilogue */ ++ key_out = grub_malloc (data.size); ++ if (!key_out) ++ { ++ err = GRUB_ERR_OUT_OF_MEMORY; ++ grub_error (err, N_("No memory left to allocate unlock key buffer")); ++ goto exit4; ++ } ++ ++ grub_memcpy (key_out, data.buffer, data.size); ++ ++ *key = key_out; ++ *key_size = data.size; ++ ++ err = GRUB_ERR_NONE; ++ ++exit4: ++ TPM2_FlushContext (sealed_key_handle); ++ ++exit3: ++ TPM2_FlushContext (session); ++ ++exit2: ++ TPM2_FlushContext (srk_handle); ++ ++exit1: ++ grub_free (sealed_key_bytes); ++ return err; ++} ++ ++static grub_err_t ++grub_tpm2_protector_nv_recover (const struct grub_tpm2_protector_context *ctx, ++ grub_uint8_t **key, grub_size_t *key_size) ++{ ++ (void)ctx; ++ (void)key; ++ (void)key_size; ++ ++ return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, ++ N_("NV Index mode is not implemented yet")); ++} ++ ++static grub_err_t ++grub_tpm2_protector_recover (const struct grub_tpm2_protector_context *ctx, ++ grub_uint8_t **key, grub_size_t *key_size) ++{ ++ switch (ctx->mode) ++ { ++ case GRUB_TPM2_PROTECTOR_MODE_SRK: ++ return grub_tpm2_protector_srk_recover (ctx, key, key_size); ++ case GRUB_TPM2_PROTECTOR_MODE_NV: ++ return grub_tpm2_protector_nv_recover (ctx, key, key_size); ++ default: ++ return GRUB_ERR_BAD_ARGUMENT; ++ } ++} ++ ++static grub_err_t ++grub_tpm2_protector_recover_key (grub_uint8_t **key, grub_size_t *key_size) ++{ ++ grub_err_t err; ++ ++ /* Expect a call to tpm2_protector_init before anybody tries to use us */ ++ if (grub_tpm2_protector_ctx.mode == GRUB_TPM2_PROTECTOR_MODE_UNSET) ++ return grub_error (GRUB_ERR_INVALID_COMMAND, ++ N_("Cannot use TPM2 key protector without initializing " ++ "it, call tpm2_protector_init first")); ++ ++ if (!key) ++ return GRUB_ERR_BAD_ARGUMENT; ++ ++ err = grub_tpm2_protector_recover (&grub_tpm2_protector_ctx, key, key_size); ++ if (err) ++ return err; ++ ++ return GRUB_ERR_NONE; ++} ++ ++ ++static grub_err_t ++grub_tpm2_protector_check_args (struct grub_tpm2_protector_context *ctx) ++{ ++ if (ctx->mode == GRUB_TPM2_PROTECTOR_MODE_UNSET) ++ ctx->mode = GRUB_TPM2_PROTECTOR_MODE_SRK; ++ ++ /* Checks for SRK mode */ ++ if (ctx->mode == GRUB_TPM2_PROTECTOR_MODE_SRK && !ctx->keyfile) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("In SRK mode, a key file must be specified: " ++ "--keyfile or -k")); ++ ++ if (ctx->mode == GRUB_TPM2_PROTECTOR_MODE_SRK && ctx->nv) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("In SRK mode, an NV Index cannot be specified")); ++ ++ /* Checks for NV mode */ ++ if (ctx->mode == GRUB_TPM2_PROTECTOR_MODE_NV && !ctx->nv) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("In NV Index mode, an NV Index must be specified: " ++ "--nvindex or -n")); ++ ++ if (ctx->mode == GRUB_TPM2_PROTECTOR_MODE_NV && ctx->keyfile) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("In NV Index mode, a keyfile cannot be specified")); ++ ++ if (ctx->mode == GRUB_TPM2_PROTECTOR_MODE_NV && ctx->srk) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("In NV Index mode, an SRK cannot be specified")); ++ ++ if (ctx->mode == GRUB_TPM2_PROTECTOR_MODE_NV && ctx->asymmetric) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("In NV Index mode, an asymmetric key type cannot be " ++ "specified")); ++ ++ /* Defaults assignment */ ++ if (!ctx->bank) ++ ctx->bank = TPM_ALG_SHA256; ++ ++ if (!ctx->pcr_count) ++ { ++ ctx->pcrs[0] = 7; ++ ctx->pcr_count = 1; ++ } ++ ++ if (ctx->mode == GRUB_TPM2_PROTECTOR_MODE_SRK) ++ { ++ if (!ctx->srk) ++ ctx->srk = TPM2_SRK_HANDLE; ++ ++ if (!ctx->asymmetric) ++ ctx->asymmetric = TPM_ALG_RSA; ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_tpm2_protector_parse_keyfile (const char *value, const char **keyfile) ++{ ++ if (grub_strlen (value) == 0) ++ return GRUB_ERR_BAD_ARGUMENT; ++ ++ *keyfile = grub_strdup (value); ++ if (!*keyfile) ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ N_("No memory to duplicate keyfile path")); ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_tpm2_protector_parse_mode (const char *value, ++ grub_tpm2_protector_mode_t *mode) ++{ ++ if (grub_strcmp (value, "srk") == 0) ++ *mode = GRUB_TPM2_PROTECTOR_MODE_SRK; ++ else if (grub_strcmp (value, "nv") == 0) ++ *mode = GRUB_TPM2_PROTECTOR_MODE_NV; ++ else ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, ++ N_("Value '%s' is not a valid TPM2 key protector mode"), ++ value); ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_tpm2_protector_init_cmd_handler (grub_extcmd_context_t ctxt, int argc, ++ char **args __attribute__ ((unused))) ++{ ++ struct grub_arg_list *state = ctxt->state; ++ grub_err_t err; ++ ++ if (argc) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("The TPM2 key protector does not accept any " ++ "non-option arguments (i.e., like -o and/or --option " ++ "only)")); ++ ++ grub_free ((void *) grub_tpm2_protector_ctx.keyfile); ++ grub_memset (&grub_tpm2_protector_ctx, 0, sizeof (grub_tpm2_protector_ctx)); ++ ++ if (state[0].set) /* mode */ ++ { ++ err = grub_tpm2_protector_parse_mode (state[0].arg, ++ &grub_tpm2_protector_ctx.mode); ++ if (err) ++ return err; ++ } ++ ++ if (state[1].set) /* pcrs */ ++ { ++ err = grub_tpm2_protector_parse_pcrs (state[1].arg, ++ grub_tpm2_protector_ctx.pcrs, ++ &grub_tpm2_protector_ctx.pcr_count); ++ if (err) ++ return err; ++ } ++ ++ if (state[2].set) /* bank */ ++ { ++ err = grub_tpm2_protector_parse_bank (state[2].arg, ++ &grub_tpm2_protector_ctx.bank); ++ if (err) ++ return err; ++ } ++ ++ if (state[3].set) /* keyfile */ ++ { ++ err = grub_tpm2_protector_parse_keyfile (state[3].arg, ++ &grub_tpm2_protector_ctx.keyfile); ++ if (err) ++ return err; ++ } ++ ++ if (state[4].set) /* srk */ ++ { ++ err = grub_tpm2_protector_parse_tpm_handle (state[4].arg, ++ &grub_tpm2_protector_ctx.srk); ++ if (err) ++ return err; ++ } ++ ++ if (state[5].set) /* asymmetric */ ++ { ++ err = grub_tpm2_protector_parse_asymmetric (state[5].arg, ++ &grub_tpm2_protector_ctx.asymmetric); ++ if (err) ++ return err; ++ } ++ ++ if (state[6].set) /* nvindex */ ++ { ++ err = grub_tpm2_protector_parse_tpm_handle (state[6].arg, ++ &grub_tpm2_protector_ctx.nv); ++ if (err) ++ return err; ++ } ++ ++ err = grub_tpm2_protector_check_args (&grub_tpm2_protector_ctx); ++ ++ /* This command only initializes the protector, so nothing else to do. */ ++ ++ return err; ++} ++ ++static grub_err_t ++grub_tpm2_protector_clear_cmd_handler (grub_extcmd_context_t ctxt __attribute__ ((unused)), ++ int argc, ++ char **args __attribute__ ((unused))) ++{ ++ if (argc) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("tpm2_key_protector_clear accepts no arguments")); ++ ++ grub_free ((void *) grub_tpm2_protector_ctx.keyfile); ++ grub_memset (&grub_tpm2_protector_ctx, 0, sizeof (grub_tpm2_protector_ctx)); ++ ++ return GRUB_ERR_NONE; ++} ++ ++static struct grub_key_protector grub_tpm2_key_protector = ++ { ++ .name = "tpm2", ++ .recover_key = grub_tpm2_protector_recover_key ++ }; ++ ++GRUB_MOD_INIT (tpm2) ++{ ++ grub_tpm2_protector_init_cmd = ++ grub_register_extcmd ("tpm2_key_protector_init", ++ grub_tpm2_protector_init_cmd_handler, 0, ++ N_("[-m mode] " ++ "[-p pcr_list] " ++ "[-b pcr_bank] " ++ "[-k sealed_key_file_path] " ++ "[-s srk_handle] " ++ "[-a asymmetric_key_type] " ++ "[-n nv_index]"), ++ N_("Initialize the TPM2 key protector."), ++ grub_tpm2_protector_init_cmd_options); ++ grub_tpm2_protector_clear_cmd = ++ grub_register_extcmd ("tpm2_key_protector_clear", ++ grub_tpm2_protector_clear_cmd_handler, 0, NULL, ++ N_("Clear the TPM2 key protector if previously initialized."), ++ NULL); ++ grub_key_protector_register (&grub_tpm2_key_protector); ++} ++ ++GRUB_MOD_FINI (tpm2) ++{ ++ grub_free ((void *) grub_tpm2_protector_ctx.keyfile); ++ grub_memset (&grub_tpm2_protector_ctx, 0, sizeof (grub_tpm2_protector_ctx)); ++ ++ grub_key_protector_unregister (&grub_tpm2_key_protector); ++ grub_unregister_extcmd (grub_tpm2_protector_clear_cmd); ++ grub_unregister_extcmd (grub_tpm2_protector_init_cmd); ++} +diff --git a/include/grub/tpm2/internal/args.h b/include/grub/tpm2/internal/args.h +new file mode 100644 +index 0000000000..6341fce1c5 +--- /dev/null ++++ b/include/grub/tpm2/internal/args.h +@@ -0,0 +1,39 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2022 Microsoft Corporation ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#ifndef GRUB_TPM2_INTERNAL_ARGS_HEADER ++#define GRUB_TPM2_INTERNAL_ARGS_HEADER 1 ++ ++#include ++#include ++ ++grub_err_t ++grub_tpm2_protector_parse_pcrs (char *value, grub_uint8_t *pcrs, ++ grub_uint8_t *pcr_count); ++ ++grub_err_t ++grub_tpm2_protector_parse_asymmetric (const char *value, ++ TPM_ALG_ID *asymmetric); ++ ++grub_err_t ++grub_tpm2_protector_parse_bank (const char *value, TPM_ALG_ID *bank); ++ ++grub_err_t ++grub_tpm2_protector_parse_tpm_handle (const char *value, TPM_HANDLE *handle); ++ ++#endif /* ! GRUB_TPM2_INTERNAL_ARGS_HEADER */ +-- +2.34.1 + diff --git a/0013-cryptodisk-Support-key-protectors.patch b/0013-cryptodisk-Support-key-protectors.patch new file mode 100644 index 0000000..4884875 --- /dev/null +++ b/0013-cryptodisk-Support-key-protectors.patch @@ -0,0 +1,336 @@ +From 9888bf40d960339a59dc18fb6e1df5f65b4668e3 Mon Sep 17 00:00:00 2001 +From: Hernan Gatta +Date: Tue, 1 Feb 2022 05:02:56 -0800 +Subject: [PATCH 13/14] cryptodisk: Support key protectors + +Add a new parameter to cryptomount to support the key protectors framework: -k. +The parameter is used to automatically retrieve a key from specified key +protectors. The parameter may be repeated to specify any number of key +protectors. These are tried in order until one provides a usable key for any +given disk. + +Signed-off-by: +--- + Makefile.util.def | 1 + + grub-core/disk/cryptodisk.c | 166 +++++++++++++++++++++++++++++------- + include/grub/cryptodisk.h | 14 +++ + 3 files changed, 151 insertions(+), 30 deletions(-) + +diff --git a/Makefile.util.def b/Makefile.util.def +index ef5c818e0e..b3ec2a4bb6 100644 +--- a/Makefile.util.def ++++ b/Makefile.util.def +@@ -35,6 +35,7 @@ library = { + common = grub-core/kern/list.c; + common = grub-core/kern/misc.c; + common = grub-core/kern/partition.c; ++ common = grub-core/kern/protectors.c; + common = grub-core/lib/crypto.c; + common = grub-core/lib/json/json.c; + common = grub-core/disk/luks.c; +diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c +index 497097394f..00c44773fb 100644 +--- a/grub-core/disk/cryptodisk.c ++++ b/grub-core/disk/cryptodisk.c +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + + #ifdef GRUB_UTIL + #include +@@ -42,6 +43,8 @@ static const struct grub_arg_option options[] = + {"all", 'a', 0, N_("Mount all."), 0, 0}, + {"boot", 'b', 0, N_("Mount all volumes with `boot' flag set."), 0, 0}, + {"password", 'p', 0, N_("Password to open volumes."), 0, ARG_TYPE_STRING}, ++ {"protector", 'k', GRUB_ARG_OPTION_REPEATABLE, ++ N_("Unlock volume(s) using key protector(s)."), 0, ARG_TYPE_STRING}, + {0, 0, 0, 0, 0, 0} + }; + +@@ -1000,7 +1003,8 @@ grub_cryptodisk_scan_device_real (const char *name, + { + grub_err_t ret = GRUB_ERR_NONE; + grub_cryptodisk_t dev; +- grub_cryptodisk_dev_t cr; ++ grub_cryptodisk_dev_t cr, crd = NULL; ++ int i; + int askpass = 0; + char *part = NULL; + +@@ -1016,39 +1020,108 @@ grub_cryptodisk_scan_device_real (const char *name, + return NULL; + if (!dev) + continue; ++ crd = cr; ++ } + +- if (!cargs->key_len) +- { +- /* Get the passphrase from the user, if no key data. */ +- askpass = 1; +- part = grub_partition_get_name (source->partition); +- grub_printf_ (N_("Enter passphrase for %s%s%s (%s): "), source->name, +- source->partition != NULL ? "," : "", +- part != NULL ? part : N_("UNKNOWN"), +- dev->uuid); +- grub_free (part); +- +- cargs->key_data = grub_malloc (GRUB_CRYPTODISK_MAX_PASSPHRASE); +- if (cargs->key_data == NULL) +- return NULL; +- +- if (!grub_password_get ((char *) cargs->key_data, GRUB_CRYPTODISK_MAX_PASSPHRASE)) +- { +- grub_error (GRUB_ERR_BAD_ARGUMENT, "passphrase not supplied"); +- goto error; +- } +- cargs->key_len = grub_strlen ((char *) cargs->key_data); +- } ++ if (!dev) ++ { ++ grub_error (GRUB_ERR_BAD_MODULE, ++ "no cryptodisk module can handle this device"); ++ return NULL; ++ } + +- ret = cr->recover_key (source, dev, cargs); +- if (ret != GRUB_ERR_NONE) ++ if (cargs->protectors) ++ { ++ for (i = 0; cargs->protectors[i]; i++) ++ { ++ if (cargs->key_cache[i].invalid) ++ continue; ++ ++ if (!cargs->key_cache[i].key) ++ { ++ ret = grub_key_protector_recover_key (cargs->protectors[i], ++ &cargs->key_cache[i].key, ++ &cargs->key_cache[i].key_len); ++ if (ret) ++ { ++ if (grub_errno) ++ { ++ grub_print_error (); ++ grub_errno = GRUB_ERR_NONE; ++ } ++ ++ grub_dprintf ("cryptodisk", ++ "failed to recover a key from key protector " ++ "%s, will not try it again for any other " ++ "disks, if any, during this invocation of " ++ "cryptomount\n", ++ cargs->protectors[i]); ++ ++ cargs->key_cache[i].invalid = 1; ++ continue; ++ } ++ } ++ ++ cargs->key_data = cargs->key_cache[i].key; ++ cargs->key_len = cargs->key_cache[i].key_len; ++ ++ ret = crd->recover_key (source, dev, cargs); ++ if (ret) ++ { ++ part = grub_partition_get_name (source->partition); ++ grub_dprintf ("cryptodisk", ++ "recovered a key from key protector %s but it " ++ "failed to unlock %s%s%s (%s)\n", ++ cargs->protectors[i], source->name, ++ source->partition != NULL ? "," : "", ++ part != NULL ? part : N_("UNKNOWN"), dev->uuid); ++ grub_free (part); ++ continue; ++ } ++ else ++ { ++ grub_cryptodisk_insert (dev, name, source); ++ goto cleanup; ++ }; ++ } ++ ++ part = grub_partition_get_name (source->partition); ++ grub_error (GRUB_ERR_ACCESS_DENIED, ++ N_("no key protector provided a usable key for %s%s%s (%s)"), ++ source->name, source->partition != NULL ? "," : "", ++ part != NULL ? part : N_("UNKNOWN"), dev->uuid); ++ grub_free (part); + goto error; ++ } + +- grub_cryptodisk_insert (dev, name, source); ++ if (!cargs->key_len) ++ { ++ /* Get the passphrase from the user, if no key data. */ ++ askpass = 1; ++ part = grub_partition_get_name (source->partition); ++ grub_printf_ (N_("Enter passphrase for %s%s%s (%s): "), source->name, ++ source->partition != NULL ? "," : "", ++ part != NULL ? part : N_("UNKNOWN"), dev->uuid); ++ grub_free (part); ++ ++ cargs->key_data = grub_malloc (GRUB_CRYPTODISK_MAX_PASSPHRASE); ++ if (cargs->key_data == NULL) ++ goto error; ++ ++ if (!grub_password_get ((char *) cargs->key_data, GRUB_CRYPTODISK_MAX_PASSPHRASE)) ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, "passphrase not supplied"); ++ goto error; ++ } ++ cargs->key_len = grub_strlen ((char *) cargs->key_data); ++ } ++ ++ ret = crd->recover_key (source, dev, cargs); ++ if (ret != GRUB_ERR_NONE) ++ goto error; ++ ++ grub_cryptodisk_insert (dev, name, source); + +- goto cleanup; +- } +- grub_error (GRUB_ERR_BAD_MODULE, "no cryptodisk module can handle this device"); + goto cleanup; + + error: +@@ -1155,6 +1228,20 @@ grub_cryptodisk_scan_device (const char *name, + return ret; + } + ++static void ++grub_cryptodisk_clear_key_cache (struct grub_cryptomount_args *cargs) ++{ ++ int i; ++ ++ if (!cargs->key_cache) ++ return; ++ ++ for (i = 0; cargs->protectors[i]; i++) ++ grub_free (cargs->key_cache[i].key); ++ ++ grub_free (cargs->key_cache); ++} ++ + static grub_err_t + grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) + { +@@ -1167,12 +1254,25 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) + if (grub_cryptodisk_list == NULL) + return grub_error (GRUB_ERR_BAD_MODULE, "no cryptodisk modules loaded"); + ++ if (state[3].set && state[4].set) /* password and key protector */ ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, ++ "a password and a key protector cannot both be set"); ++ + if (state[3].set) /* password */ + { + cargs.key_data = (grub_uint8_t *) state[3].arg; + cargs.key_len = grub_strlen (state[3].arg); + } + ++ if (state[4].set) /* key protector(s) */ ++ { ++ cargs.key_cache = grub_zalloc (state[4].set * sizeof (*cargs.key_cache)); ++ if (!cargs.key_cache) ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "no memory for key protector key cache"); ++ cargs.protectors = state[4].args; ++ } ++ + if (state[0].set) /* uuid */ + { + int found_uuid; +@@ -1181,6 +1281,7 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) + dev = grub_cryptodisk_get_by_uuid (args[0]); + if (dev) + { ++ grub_cryptodisk_clear_key_cache (&cargs); + grub_dprintf ("cryptodisk", + "already mounted as crypto%lu\n", dev->id); + return GRUB_ERR_NONE; +@@ -1189,6 +1290,7 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) + cargs.check_boot = state[2].set; + cargs.search_uuid = args[0]; + found_uuid = grub_device_iterate (&grub_cryptodisk_scan_device, &cargs); ++ grub_cryptodisk_clear_key_cache (&cargs); + + if (found_uuid) + return GRUB_ERR_NONE; +@@ -1208,6 +1310,7 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) + { + cargs.check_boot = state[2].set; + grub_device_iterate (&grub_cryptodisk_scan_device, &cargs); ++ grub_cryptodisk_clear_key_cache (&cargs); + return GRUB_ERR_NONE; + } + else +@@ -1231,6 +1334,7 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) + disk = grub_disk_open (diskname); + if (!disk) + { ++ grub_cryptodisk_clear_key_cache (&cargs); + if (disklast) + *disklast = ')'; + return grub_errno; +@@ -1241,12 +1345,14 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) + { + grub_dprintf ("cryptodisk", "already mounted as crypto%lu\n", dev->id); + grub_disk_close (disk); ++ grub_cryptodisk_clear_key_cache (&cargs); + if (disklast) + *disklast = ')'; + return GRUB_ERR_NONE; + } + + dev = grub_cryptodisk_scan_device_real (diskname, disk, &cargs); ++ grub_cryptodisk_clear_key_cache (&cargs); + + grub_disk_close (disk); + if (disklast) +@@ -1385,7 +1491,7 @@ GRUB_MOD_INIT (cryptodisk) + { + grub_disk_dev_register (&grub_cryptodisk_dev); + cmd = grub_register_extcmd ("cryptomount", grub_cmd_cryptomount, 0, +- N_("[-p password] "), ++ N_("[-p password] [-k protector [-k protector ...]] "), + N_("Mount a crypto device."), options); + grub_procfs_register ("luks_script", &luks_script); + } +diff --git a/include/grub/cryptodisk.h b/include/grub/cryptodisk.h +index c6524c9ea9..b556498fba 100644 +--- a/include/grub/cryptodisk.h ++++ b/include/grub/cryptodisk.h +@@ -67,6 +67,16 @@ typedef gcry_err_code_t + (*grub_cryptodisk_rekey_func_t) (struct grub_cryptodisk *dev, + grub_uint64_t zoneno); + ++struct grub_cryptomount_cached_key ++{ ++ grub_uint8_t *key; ++ grub_size_t key_len; ++ ++ /* The key protector associated with this cache entry failed, so avoid it ++ * even if the cached entry (an instance of this structure) is empty. */ ++ int invalid; ++}; ++ + struct grub_cryptomount_args + { + /* scan: Flag to indicate that only bootable volumes should be decrypted */ +@@ -77,6 +87,10 @@ struct grub_cryptomount_args + grub_uint8_t *key_data; + /* recover_key: Length of key_data */ + grub_size_t key_len; ++ /* recover_key: Names of the key protectors to use (NULL-terminated) */ ++ char **protectors; ++ /* recover_key: Key cache to avoid invoking the same key protector twice */ ++ struct grub_cryptomount_cached_key *key_cache; + }; + typedef struct grub_cryptomount_args *grub_cryptomount_args_t; + +-- +2.34.1 + diff --git a/0014-util-grub-protect-Add-new-tool.patch b/0014-util-grub-protect-Add-new-tool.patch new file mode 100644 index 0000000..c423a60 --- /dev/null +++ b/0014-util-grub-protect-Add-new-tool.patch @@ -0,0 +1,1408 @@ +From a913983cb75594e08b425e3c099185b2f4187663 Mon Sep 17 00:00:00 2001 +From: Hernan Gatta +Date: Tue, 1 Feb 2022 05:02:57 -0800 +Subject: [PATCH 14/14] util/grub-protect: Add new tool + +To utilize the key protectors framework, there must be a way to protect +full-disk encryption keys in the first place. The grub-protect tool includes +support for the TPM2 key protector but other protectors that require setup ahead +of time can be supported in the future. + +For the TPM2 key protector, the intended flow is for a user to have a LUKS 1 or +LUKS 2-protected fully-encrypted disk. The user then creates a new key file, say +by reading /dev/urandom into a file, and creates a new LUKS key slot for this +key. Then, the user invokes the grub-protect tool to seal this key file to a set +of PCRs using the system's TPM 2.0. The resulting sealed key file is stored in +an unencrypted partition such as the EFI System Partition (ESP) so that GRUB may +read it. The user also ensures the cryptomount command is included in GRUB's +boot script and that it carries the requisite key protector (-k) parameter. + +Sample usage: + +$ dd if=/dev/urandom of=key bs=1 count=32 +$ sudo cryptsetup luksAddKey /dev/sdb1 key --pbkdf=pbkdf2 --hash=sha512 + +$ sudo grub-protect --action=add + --protector=tpm2 + --tpm2-keyfile=key + --tpm2-outfile=/boot/efi/boot/grub2/sealed_key + +Then, in the boot script: + +tpm2_key_protector_init -k (hd0,gpt1)/boot/grub2/sealed_key +cryptomount -u b20f95d0834842bc9197bd78b36732f8 -k tpm2 + +where the UUID corresponds to /dev/sdb1. + +Signed-off-by: Hernan Gatta +--- + Makefile.util.def | 18 + + configure.ac | 1 + + util/grub-protect.c | 1314 +++++++++++++++++++++++++++++++++++++++++++ + 4 files changed, 1334 insertions(+) + create mode 100644 util/grub-protect.c + +diff --git a/Makefile.util.def b/Makefile.util.def +index b3ec2a4bb6..08f681cd8b 100644 +--- a/Makefile.util.def ++++ b/Makefile.util.def +@@ -207,6 +207,24 @@ program = { + ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; + }; + ++program = { ++ name = grub-protect; ++ ++ common = grub-core/osdep/init.c; ++ common = grub-core/tpm2/args.c; ++ common = grub-core/tpm2/buffer.c; ++ common = grub-core/tpm2/mu.c; ++ common = grub-core/tpm2/tpm2.c; ++ common = util/grub-protect.c; ++ common = util/probe.c; ++ ++ ldadd = libgrubmods.a; ++ ldadd = libgrubgcry.a; ++ ldadd = libgrubkern.a; ++ ldadd = grub-core/lib/gnulib/libgnu.a; ++ ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; ++}; ++ + program = { + name = grub-mkrelpath; + mansection = 1; +diff --git a/configure.ac b/configure.ac +index 906eb1cedc..ba717a9600 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -71,6 +71,7 @@ grub_TRANSFORM([grub-mkpasswd-pbkdf2]) + grub_TRANSFORM([grub-mkrelpath]) + grub_TRANSFORM([grub-mkrescue]) + grub_TRANSFORM([grub-probe]) ++grub_TRANSFORM([grub-protect]) + grub_TRANSFORM([grub-reboot]) + grub_TRANSFORM([grub-script-check]) + grub_TRANSFORM([grub-set-default]) +diff --git a/util/grub-protect.c b/util/grub-protect.c +new file mode 100644 +index 0000000000..23ee78d32a +--- /dev/null ++++ b/util/grub-protect.c +@@ -0,0 +1,1314 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2022 Microsoft Corporation ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#pragma GCC diagnostic ignored "-Wmissing-prototypes" ++#pragma GCC diagnostic ignored "-Wmissing-declarations" ++#include ++#pragma GCC diagnostic error "-Wmissing-prototypes" ++#pragma GCC diagnostic error "-Wmissing-declarations" ++ ++#include "progname.h" ++ ++/* Unprintable option keys for argp */ ++typedef enum grub_protect_opt ++{ ++ /* General */ ++ GRUB_PROTECT_OPT_ACTION = 'a', ++ GRUB_PROTECT_OPT_PROTECTOR = 'p', ++ /* TPM2 */ ++ GRUB_PROTECT_OPT_TPM2_DEVICE = 0x100, ++ GRUB_PROTECT_OPT_TPM2_PCRS, ++ GRUB_PROTECT_OPT_TPM2_ASYMMETRIC, ++ GRUB_PROTECT_OPT_TPM2_BANK, ++ GRUB_PROTECT_OPT_TPM2_SRK, ++ GRUB_PROTECT_OPT_TPM2_KEYFILE, ++ GRUB_PROTECT_OPT_TPM2_OUTFILE, ++ GRUB_PROTECT_OPT_TPM2_PERSIST, ++ GRUB_PROTECT_OPT_TPM2_EVICT ++} grub_protect_opt; ++ ++/* Option flags to keep track of specified arguments */ ++typedef enum grub_protect_arg ++{ ++ /* General */ ++ GRUB_PROTECT_ARG_ACTION = 1 << 0, ++ GRUB_PROTECT_ARG_PROTECTOR = 1 << 1, ++ /* TPM2 */ ++ GRUB_PROTECT_ARG_TPM2_DEVICE = 1 << 2, ++ GRUB_PROTECT_ARG_TPM2_PCRS = 1 << 3, ++ GRUB_PROTECT_ARG_TPM2_ASYMMETRIC = 1 << 4, ++ GRUB_PROTECT_ARG_TPM2_BANK = 1 << 5, ++ GRUB_PROTECT_ARG_TPM2_SRK = 1 << 6, ++ GRUB_PROTECT_ARG_TPM2_KEYFILE = 1 << 7, ++ GRUB_PROTECT_ARG_TPM2_OUTFILE = 1 << 8, ++ GRUB_PROTECT_ARG_TPM2_PERSIST = 1 << 9, ++ GRUB_PROTECT_ARG_TPM2_EVICT = 1 << 10 ++} grub_protect_arg_t; ++ ++typedef enum grub_protect_protector ++{ ++ GRUB_PROTECT_TYPE_ERROR, ++ GRUB_PROTECT_TYPE_TPM2 ++} grub_protect_protector_t; ++ ++typedef enum grub_protect_action ++{ ++ GRUB_PROTECT_ACTION_ERROR, ++ GRUB_PROTECT_ACTION_ADD, ++ GRUB_PROTECT_ACTION_REMOVE ++} grub_protect_action_t; ++ ++struct grub_protect_args ++{ ++ grub_protect_arg_t args; ++ grub_protect_action_t action; ++ grub_protect_protector_t protector; ++ ++ const char *tpm2_device; ++ grub_uint8_t tpm2_pcrs[TPM_MAX_PCRS]; ++ grub_uint8_t tpm2_pcr_count; ++ TPM_ALG_ID tpm2_asymmetric; ++ TPM_ALG_ID tpm2_bank; ++ TPM_HANDLE tpm2_srk; ++ const char *tpm2_keyfile; ++ const char *tpm2_outfile; ++ int tpm2_persist; ++ int tpm2_evict; ++}; ++ ++static struct argp_option grub_protect_options[] = ++ { ++ /* Top-level options */ ++ { ++ .name = "action", ++ .key = 'a', ++ .arg = "ADD|REMOVE", ++ .flags = 0, ++ .doc = ++ N_("Add or remove a key protector to or from a key."), ++ .group = 0 ++ }, ++ { ++ .name = "protector", ++ .key = 'p', ++ .arg = "TPM2", ++ .flags = 0, ++ .doc = ++ N_("Key protector to use (only TPM2 is currently supported)."), ++ .group = 0 ++ }, ++ /* TPM2 key protector options */ ++ { ++ .name = "tpm2-device", ++ .key = GRUB_PROTECT_OPT_TPM2_DEVICE, ++ .arg = "FILE", ++ .flags = 0, ++ .doc = ++ N_("Path to the TPM2 device (default is /dev/tpm0)."), ++ .group = 0 ++ }, ++ { ++ .name = "tpm2-pcrs", ++ .key = GRUB_PROTECT_OPT_TPM2_PCRS, ++ .arg = "0[,1]...", ++ .flags = 0, ++ .doc = ++ N_("Comma-separated list of PCRs used to authorize key release " ++ "(e.g., '7,11', default is 7."), ++ .group = 0 ++ }, ++ { ++ .name = "tpm2-bank", ++ .key = GRUB_PROTECT_OPT_TPM2_BANK, ++ .arg = "SHA1|SHA256|SHA384", ++ .flags = 0, ++ .doc = ++ N_("Bank of PCRs used to authorize key release: " ++ "SHA1, SHA256 (default), or SHA384."), ++ .group = 0 ++ }, ++ { ++ .name = "tpm2-keyfile", ++ .key = GRUB_PROTECT_OPT_TPM2_KEYFILE, ++ .arg = "FILE", ++ .flags = 0, ++ .doc = ++ N_("Path to a file that contains the cleartext key to protect."), ++ .group = 0 ++ }, ++ { ++ .name = "tpm2-outfile", ++ .key = GRUB_PROTECT_OPT_TPM2_OUTFILE, ++ .arg = "FILE", ++ .flags = 0, ++ .doc = ++ N_("Path to the file that will contain the key after sealing (must be " ++ "accessible to GRUB during boot)."), ++ .group = 0 ++ }, ++ { ++ .name = "tpm2-srk", ++ .key = GRUB_PROTECT_OPT_TPM2_SRK, ++ .arg = "NUM", ++ .flags = 0, ++ .doc = ++ N_("The SRK handle if the SRK is to be made persistent " ++ "(default is 0x81000001)."), ++ .group = 0 ++ }, ++ { ++ .name = "tpm2-asymmetric", ++ .key = GRUB_PROTECT_OPT_TPM2_ASYMMETRIC, ++ .arg = "RSA|ECC", ++ .flags = 0, ++ .doc = ++ N_("The type of SRK: RSA (default) or ECC."), ++ .group = 0 ++ }, ++ { ++ .name = "tpm2-persist", ++ .key = GRUB_PROTECT_OPT_TPM2_PERSIST, ++ .arg = NULL, ++ .flags = 0, ++ .doc = ++ N_("Whether to persist the SRK onto the TPM, otherwise it is recreated " ++ "ephemerally during boot (default is to not persist it)."), ++ .group = 0 ++ }, ++ { ++ .name = "tpm2-evict", ++ .key = GRUB_PROTECT_OPT_TPM2_EVICT, ++ .arg = NULL, ++ .flags = 0, ++ .doc = ++ N_("Evict a previously persisted SRK from the TPM, if any."), ++ .group = 0 ++ }, ++ /* End of list */ ++ { 0, 0, 0, 0, 0, 0 } ++ }; ++ ++static int grub_protector_tpm2_fd = -1; ++ ++static grub_err_t ++grub_protect_read_file (const char *filepath, void **buffer, ++ size_t *buffer_size) ++{ ++ grub_err_t err; ++ FILE *f; ++ long len; ++ void *buf; ++ ++ f = fopen (filepath, "rb"); ++ if (!f) ++ return GRUB_ERR_FILE_NOT_FOUND; ++ ++ if (fseek (f, 0, SEEK_END)) ++ { ++ err = GRUB_ERR_FILE_READ_ERROR; ++ goto exit1; ++ } ++ ++ len = ftell (f); ++ if (!len) ++ { ++ err = GRUB_ERR_FILE_READ_ERROR; ++ goto exit1; ++ } ++ ++ rewind (f); ++ ++ buf = grub_malloc (len); ++ if (!buf) ++ { ++ err = GRUB_ERR_OUT_OF_MEMORY; ++ goto exit1; ++ } ++ ++ if (fread (buf, len, 1, f) != 1) ++ { ++ err = GRUB_ERR_FILE_READ_ERROR; ++ goto exit2; ++ } ++ ++ *buffer = buf; ++ *buffer_size = len; ++ ++ buf = NULL; ++ err = GRUB_ERR_NONE; ++ ++exit2: ++ grub_free (buf); ++ ++exit1: ++ fclose (f); ++ ++ return err; ++} ++ ++static grub_err_t ++grub_protect_write_file (const char *filepath, void *buffer, size_t buffer_size) ++{ ++ grub_err_t err; ++ FILE *f; ++ ++ f = fopen (filepath, "wb"); ++ if (!f) ++ return GRUB_ERR_FILE_NOT_FOUND; ++ ++ if (fwrite (buffer, buffer_size, 1, f) != 1) ++ { ++ err = GRUB_ERR_WRITE_ERROR; ++ goto exit1; ++ } ++ ++ err = GRUB_ERR_NONE; ++ ++exit1: ++ fclose (f); ++ ++ return err; ++} ++ ++static grub_err_t ++grub_protect_get_grub_drive_for_file (const char *filepath, char **drive) ++{ ++ grub_err_t err = GRUB_ERR_IO; ++ char *disk; ++ char **devices; ++ char *grub_dev; ++ char *grub_path; ++ char *efi_drive; ++ char *partition; ++ char *grub_drive; ++ grub_device_t dev; ++ grub_size_t grub_drive_len; ++ int n; ++ ++ grub_path = grub_canonicalize_file_name (filepath); ++ if (!grub_path) ++ goto exit1; ++ ++ devices = grub_guess_root_devices (grub_path); ++ if (!devices || !devices[0]) ++ goto exit2; ++ ++ disk = devices[0]; ++ ++ grub_util_pull_device (disk); ++ ++ grub_dev = grub_util_get_grub_dev (disk); ++ if (!grub_dev) ++ goto exit3; ++ ++ dev = grub_device_open (grub_dev); ++ if (!dev) ++ goto exit4; ++ ++ efi_drive = grub_util_guess_efi_drive (disk); ++ if (!efi_drive) ++ goto exit5; ++ ++ partition = grub_partition_get_name (dev->disk->partition); ++ if (!partition) ++ goto exit6; ++ ++ grub_drive_len = grub_strlen (efi_drive) + grub_strlen (partition) + 3; ++ grub_drive = grub_malloc (grub_drive_len + 1); ++ if (!grub_drive) ++ goto exit7; ++ ++ n = grub_snprintf (grub_drive, grub_drive_len + 1, "(%s,%s)", efi_drive, ++ partition); ++ if (n != grub_drive_len) ++ goto exit8; ++ ++ *drive = grub_drive; ++ grub_drive = NULL; ++ err = GRUB_ERR_NONE; ++ ++exit8: ++ grub_free (grub_drive); ++ ++exit7: ++ grub_free (partition); ++ ++exit6: ++ grub_free (efi_drive); ++ ++exit5: ++ grub_device_close (dev); ++ ++exit4: ++ grub_free (grub_dev); ++ ++exit3: ++ grub_free (devices); ++ ++exit2: ++ grub_free (grub_path); ++ ++exit1: ++ return err; ++} ++ ++grub_err_t ++grub_tcg2_get_max_output_size (grub_size_t *size) ++{ ++ if (!size) ++ return GRUB_ERR_BAD_ARGUMENT; ++ ++ *size = GRUB_TPM2_BUFFER_CAPACITY; ++ ++ return GRUB_ERR_NONE; ++} ++ ++grub_err_t ++grub_tcg2_submit_command (grub_size_t input_size, grub_uint8_t *input, ++ grub_size_t output_size, grub_uint8_t *output) ++{ ++ static const grub_size_t header_size = sizeof (grub_uint16_t) + ++ (2 * sizeof(grub_uint32_t)); ++ ++ if (write (grub_protector_tpm2_fd, input, input_size) != input_size) ++ return GRUB_ERR_BAD_DEVICE; ++ ++ if (read (grub_protector_tpm2_fd, output, output_size) < header_size) ++ return GRUB_ERR_BAD_DEVICE; ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_protect_tpm2_open_device (const char *dev_node) ++{ ++ if (grub_protector_tpm2_fd != -1) ++ return GRUB_ERR_NONE; ++ ++ grub_protector_tpm2_fd = open (dev_node, O_RDWR); ++ if (grub_protector_tpm2_fd == -1) ++ { ++ fprintf (stderr, _("Could not open TPM device (Error: %u).\n"), errno); ++ return GRUB_ERR_FILE_NOT_FOUND; ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_protect_tpm2_close_device (void) ++{ ++ int err; ++ ++ if (grub_protector_tpm2_fd == -1) ++ return GRUB_ERR_NONE; ++ ++ err = close (grub_protector_tpm2_fd); ++ if (err) ++ { ++ fprintf (stderr, _("Could not close TPM device (Error: %u).\n"), errno); ++ return GRUB_ERR_IO; ++ } ++ ++ grub_protector_tpm2_fd = -1; ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_protect_tpm2_get_policy_digest (struct grub_protect_args *args, ++ TPM2B_DIGEST *digest) ++{ ++ TPM_RC rc; ++ TPML_PCR_SELECTION pcr_sel = { ++ .count = 1, ++ .pcrSelections = { ++ { ++ .hash = args->tpm2_bank, ++ .sizeOfSelect = 3, ++ .pcrSelect = { 0 } ++ }, ++ } ++ }; ++ TPML_PCR_SELECTION pcr_sel_out = { 0 }; ++ TPML_DIGEST pcr_values = { 0 }; ++ grub_uint8_t *pcr_digest; ++ grub_size_t pcr_digest_len; ++ grub_uint8_t *pcr_concat; ++ grub_size_t pcr_concat_len; ++ grub_uint8_t *pcr_cursor; ++ const gcry_md_spec_t *hash_spec; ++ TPM2B_NONCE nonce = { 0 }; ++ TPM2B_ENCRYPTED_SECRET salt = { 0 }; ++ TPMT_SYM_DEF symmetric = { 0 }; ++ TPMI_SH_AUTH_SESSION session = 0; ++ TPM2B_DIGEST pcr_digest_in = { ++ .size = TPM_SHA256_DIGEST_SIZE, ++ .buffer = { 0 } ++ }; ++ TPM2B_DIGEST policy_digest = { 0 }; ++ grub_uint8_t i; ++ grub_err_t err; ++ ++ /* PCR Read */ ++ for (i = 0; i < args->tpm2_pcr_count; i++) ++ pcr_sel ++ .pcrSelections[0] ++ .pcrSelect[TPM2_PCR_TO_SELECT(args->tpm2_pcrs[i])] ++ |= TPM2_PCR_TO_BIT(args->tpm2_pcrs[i]); ++ ++ rc = TPM2_PCR_Read (NULL, &pcr_sel, NULL, &pcr_sel_out, &pcr_values, NULL); ++ if (rc != TPM_RC_SUCCESS) ++ { ++ fprintf (stderr, _("Failed to read PCRs (TPM error: 0x%x).\n"), rc); ++ return GRUB_ERR_BAD_DEVICE; ++ } ++ ++ if ((pcr_sel_out.count != pcr_sel.count) || ++ (pcr_sel.pcrSelections[0].sizeOfSelect != ++ pcr_sel_out.pcrSelections[0].sizeOfSelect)) ++ { ++ fprintf (stderr, _("Could not read all the specified PCRs.\n")); ++ return GRUB_ERR_BAD_DEVICE; ++ } ++ ++ /* Compute PCR Digest */ ++ switch (args->tpm2_bank) ++ { ++ case TPM_ALG_SHA1: ++ pcr_digest_len = TPM_SHA1_DIGEST_SIZE; ++ hash_spec = GRUB_MD_SHA1; ++ break; ++ case TPM_ALG_SHA256: ++ pcr_digest_len = TPM_SHA256_DIGEST_SIZE; ++ hash_spec = GRUB_MD_SHA256; ++ break; ++ default: ++ return GRUB_ERR_BAD_ARGUMENT; ++ } ++ ++ pcr_digest = grub_malloc (pcr_digest_len); ++ if (!pcr_digest) ++ { ++ fprintf (stderr, _("Failed to allocate PCR digest buffer.\n")); ++ return GRUB_ERR_OUT_OF_MEMORY; ++ } ++ ++ pcr_concat_len = pcr_digest_len * args->tpm2_pcr_count; ++ pcr_concat = grub_malloc (pcr_concat_len); ++ if (!pcr_concat) ++ { ++ err = GRUB_ERR_OUT_OF_MEMORY; ++ fprintf (stderr, _("Failed to allocate PCR concatenation buffer.\n")); ++ goto exit1; ++ } ++ ++ pcr_cursor = pcr_concat; ++ for (i = 0; i < args->tpm2_pcr_count; i++) ++ { ++ if (pcr_values.digests[i].size != pcr_digest_len) ++ { ++ fprintf (stderr, ++ _("Bad PCR value size: expected %lu bytes but got %u bytes.\n"), ++ pcr_digest_len, pcr_values.digests[i].size); ++ goto exit2; ++ } ++ ++ grub_memcpy (pcr_cursor, pcr_values.digests[i].buffer, pcr_digest_len); ++ pcr_cursor += pcr_digest_len; ++ } ++ ++ grub_crypto_hash (hash_spec, pcr_digest, pcr_concat, pcr_concat_len); ++ ++ /* Start Trial Session */ ++ nonce.size = TPM_SHA256_DIGEST_SIZE; ++ symmetric.algorithm = TPM_ALG_NULL; ++ ++ rc = TPM2_StartAuthSession (TPM_RH_NULL, TPM_RH_NULL, 0, &nonce, &salt, ++ TPM_SE_TRIAL, &symmetric, TPM_ALG_SHA256, ++ &session, NULL, 0); ++ if (rc != TPM_RC_SUCCESS) ++ { ++ fprintf (stderr, ++ _("Failed to start trial policy session (TPM error: 0x%x).\n"), ++ rc); ++ err = GRUB_ERR_BAD_DEVICE; ++ goto exit2; ++ } ++ ++ /* PCR Policy */ ++ memcpy (pcr_digest_in.buffer, pcr_digest, TPM_SHA256_DIGEST_SIZE); ++ ++ rc = TPM2_PolicyPCR (session, NULL, &pcr_digest_in, &pcr_sel, NULL); ++ if (rc != TPM_RC_SUCCESS) ++ { ++ fprintf (stderr, _("Failed to submit PCR policy (TPM error: 0x%x).\n"), ++ rc); ++ err = GRUB_ERR_BAD_DEVICE; ++ goto exit3; ++ } ++ ++ /* Retrieve Policy Digest */ ++ rc = TPM2_PolicyGetDigest (session, NULL, &policy_digest, NULL); ++ if (rc != TPM_RC_SUCCESS) ++ { ++ fprintf (stderr, _("Failed to get policy digest (TPM error: 0x%x).\n"), ++ rc); ++ err = GRUB_ERR_BAD_DEVICE; ++ goto exit3; ++ } ++ ++ /* Epilogue */ ++ *digest = policy_digest; ++ err = GRUB_ERR_NONE; ++ ++exit3: ++ TPM2_FlushContext (session); ++ ++exit2: ++ grub_free (pcr_concat); ++ ++exit1: ++ grub_free (pcr_digest); ++ ++ return err; ++} ++ ++static grub_err_t ++grub_protect_tpm2_get_srk (struct grub_protect_args *args, TPM_HANDLE *srk) ++{ ++ TPM_RC rc; ++ TPM2B_PUBLIC public; ++ TPMS_AUTH_COMMAND authCommand = { 0 }; ++ TPM2B_SENSITIVE_CREATE inSensitive = { 0 }; ++ TPM2B_PUBLIC inPublic = { 0 }; ++ TPM2B_DATA outsideInfo = { 0 }; ++ TPML_PCR_SELECTION creationPcr = { 0 }; ++ TPM2B_PUBLIC outPublic = { 0 }; ++ TPM2B_CREATION_DATA creationData = { 0 }; ++ TPM2B_DIGEST creationHash = { 0 }; ++ TPMT_TK_CREATION creationTicket = { 0 }; ++ TPM2B_NAME srkName = { 0 }; ++ TPM_HANDLE srkHandle; ++ ++ /* Find SRK */ ++ rc = TPM2_ReadPublic (args->tpm2_srk, NULL, &public); ++ if (rc == TPM_RC_SUCCESS) ++ { ++ if (args->tpm2_persist) ++ fprintf (stderr, ++ _("Warning: --tpm2-persist was specified but the SRK already " ++ "exists on the TPM. Continuing anyway...\n")); ++ ++ *srk = TPM2_SRK_HANDLE; ++ return GRUB_ERR_NONE; ++ } ++ ++ /* The handle exists but its public area could not be read. */ ++ if ((rc & ~TPM_RC_N_MASK) != TPM_RC_HANDLE) ++ { ++ fprintf (stderr, ++ _("The SRK exists on the TPM but its public area cannot be read " ++ "(TPM error: 0x%x).\n"), rc); ++ return GRUB_ERR_BAD_DEVICE; ++ } ++ ++ /* Create SRK */ ++ authCommand.sessionHandle = TPM_RS_PW; ++ inPublic.publicArea.type = args->tpm2_asymmetric; ++ inPublic.publicArea.nameAlg = TPM_ALG_SHA256; ++ inPublic.publicArea.objectAttributes.restricted = 1; ++ inPublic.publicArea.objectAttributes.userWithAuth = 1; ++ inPublic.publicArea.objectAttributes.decrypt = 1; ++ inPublic.publicArea.objectAttributes.fixedTPM = 1; ++ inPublic.publicArea.objectAttributes.fixedParent = 1; ++ inPublic.publicArea.objectAttributes.sensitiveDataOrigin = 1; ++ inPublic.publicArea.objectAttributes.noDA = 1; ++ ++ switch (args->tpm2_asymmetric) ++ { ++ case TPM_ALG_RSA: ++ inPublic.publicArea.parameters.rsaDetail.symmetric.algorithm = TPM_ALG_AES; ++ inPublic.publicArea.parameters.rsaDetail.symmetric.keyBits.aes = 128; ++ inPublic.publicArea.parameters.rsaDetail.symmetric.mode.aes = TPM_ALG_CFB; ++ inPublic.publicArea.parameters.rsaDetail.scheme.scheme = TPM_ALG_NULL; ++ inPublic.publicArea.parameters.rsaDetail.keyBits = 2048; ++ inPublic.publicArea.parameters.rsaDetail.exponent = 0; ++ break; ++ ++ case TPM_ALG_ECC: ++ inPublic.publicArea.parameters.eccDetail.symmetric.algorithm = TPM_ALG_AES; ++ inPublic.publicArea.parameters.eccDetail.symmetric.keyBits.aes = 128; ++ inPublic.publicArea.parameters.eccDetail.symmetric.mode.aes = TPM_ALG_CFB; ++ inPublic.publicArea.parameters.eccDetail.scheme.scheme = TPM_ALG_NULL; ++ inPublic.publicArea.parameters.eccDetail.curveID = TPM_ECC_NIST_P256; ++ inPublic.publicArea.parameters.eccDetail.kdf.scheme = TPM_ALG_NULL; ++ break; ++ ++ default: ++ return GRUB_ERR_BAD_ARGUMENT; ++ } ++ ++ rc = TPM2_CreatePrimary (TPM_RH_OWNER, &authCommand, &inSensitive, &inPublic, ++ &outsideInfo, &creationPcr, &srkHandle, &outPublic, ++ &creationData, &creationHash, &creationTicket, ++ &srkName, NULL); ++ if (rc != TPM_RC_SUCCESS) ++ { ++ fprintf (stderr, _("Failed to create SRK (TPM error: 0x%x).\n"), rc); ++ return GRUB_ERR_BAD_DEVICE; ++ } ++ ++ /* Persist SRK */ ++ if (args->tpm2_persist) ++ { ++ rc = TPM2_EvictControl (TPM_RH_OWNER, srkHandle, args->tpm2_srk, ++ &authCommand, NULL); ++ if (rc == TPM_RC_SUCCESS) ++ { ++ TPM2_FlushContext (srkHandle); ++ srkHandle = args->tpm2_srk; ++ } ++ else ++ fprintf (stderr, ++ _("Warning: Failed to persist SRK (TPM error: 0x%x\n). " ++ "Continuing anyway...\n"), rc); ++ } ++ ++ /* Epilogue */ ++ *srk = srkHandle; ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_protect_tpm2_seal (TPM2B_DIGEST *policyDigest, TPM_HANDLE srk, ++ grub_uint8_t *clearText, grub_size_t clearTextLength, ++ TPM2_SEALED_KEY *sealed_key) ++{ ++ TPM_RC rc; ++ TPMS_AUTH_COMMAND authCommand = { 0 }; ++ TPM2B_SENSITIVE_CREATE inSensitive = { 0 }; ++ TPM2B_PUBLIC inPublic = { 0 }; ++ TPM2B_DATA outsideInfo = { 0 }; ++ TPML_PCR_SELECTION pcr_sel = { 0 }; ++ TPM2B_PRIVATE outPrivate = { 0 }; ++ TPM2B_PUBLIC outPublic = { 0 }; ++ ++ /* Seal Data */ ++ authCommand.sessionHandle = TPM_RS_PW; ++ ++ inSensitive.sensitive.data.size = clearTextLength; ++ memcpy(inSensitive.sensitive.data.buffer, clearText, clearTextLength); ++ ++ inPublic.publicArea.type = TPM_ALG_KEYEDHASH; ++ inPublic.publicArea.nameAlg = TPM_ALG_SHA256; ++ inPublic.publicArea.parameters.keyedHashDetail.scheme.scheme = TPM_ALG_NULL; ++ inPublic.publicArea.authPolicy = *policyDigest; ++ ++ rc = TPM2_Create (srk, &authCommand, &inSensitive, &inPublic, &outsideInfo, ++ &pcr_sel, &outPrivate, &outPublic, NULL, NULL, NULL, NULL); ++ if (rc != TPM_RC_SUCCESS) ++ { ++ fprintf (stderr, _("Failed to seal key (TPM error: 0x%x).\n"), rc); ++ return GRUB_ERR_BAD_DEVICE; ++ } ++ ++ /* Epilogue */ ++ sealed_key->public = outPublic; ++ sealed_key->private = outPrivate; ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_protect_tpm2_export_sealed_key (const char *filepath, ++ TPM2_SEALED_KEY *sealed_key) ++{ ++ grub_err_t err; ++ struct grub_tpm2_buffer buf; ++ ++ grub_tpm2_buffer_init (&buf); ++ grub_tpm2_mu_TPM2B_PUBLIC_Marshal (&buf, &sealed_key->public); ++ grub_tpm2_mu_TPM2B_Marshal (&buf, sealed_key->private.size, ++ sealed_key->private.buffer); ++ if (buf.error) ++ return GRUB_ERR_BAD_ARGUMENT; ++ ++ err = grub_protect_write_file (filepath, buf.data, buf.size); ++ if (err) ++ fprintf (stderr, _("Could not write sealed key file (Error: %u).\n"), ++ errno); ++ ++ return err; ++} ++ ++static grub_err_t ++grub_protect_tpm2_add (struct grub_protect_args *args) ++{ ++ grub_err_t err; ++ grub_uint8_t *key; ++ grub_size_t key_size; ++ TPM_HANDLE srk; ++ TPM2B_DIGEST policy_digest; ++ TPM2_SEALED_KEY sealed_key; ++ char *grub_drive = NULL; ++ ++ grub_protect_get_grub_drive_for_file (args->tpm2_outfile, &grub_drive); ++ ++ err = grub_protect_tpm2_open_device (args->tpm2_device); ++ if (err) ++ return err; ++ ++ err = grub_protect_read_file (args->tpm2_keyfile, (void **)&key, &key_size); ++ if (err) ++ goto exit1; ++ ++ if (key_size > TPM_MAX_SYM_DATA) ++ { ++ fprintf (stderr, ++ _("Input key is too long, maximum allowed size is %u bytes.\n"), ++ TPM_MAX_SYM_DATA); ++ return GRUB_ERR_OUT_OF_RANGE; ++ } ++ ++ err = grub_protect_tpm2_get_srk (args, &srk); ++ if (err) ++ goto exit2; ++ ++ err = grub_protect_tpm2_get_policy_digest (args, &policy_digest); ++ if (err) ++ goto exit3; ++ ++ err = grub_protect_tpm2_seal (&policy_digest, srk, key, key_size, ++ &sealed_key); ++ if (err) ++ goto exit3; ++ ++ err = grub_protect_tpm2_export_sealed_key (args->tpm2_outfile, &sealed_key); ++ if (err) ++ goto exit3; ++ ++ if (grub_drive) ++ { ++ printf (_("GRUB drive for the sealed key file: %s\n"), grub_drive); ++ grub_free (grub_drive); ++ } ++ else ++ { ++ fprintf (stderr, ++ _("Warning: Could not determine GRUB drive for sealed key " ++ "file.\n")); ++ err = GRUB_ERR_NONE; ++ } ++ ++exit3: ++ TPM2_FlushContext (srk); ++ ++exit2: ++ grub_free (key); ++ ++exit1: ++ grub_protect_tpm2_close_device (); ++ ++ return err; ++} ++ ++static grub_err_t ++grub_protect_tpm2_remove (struct grub_protect_args *args) ++{ ++ TPM_RC rc; ++ TPM2B_PUBLIC public; ++ TPMS_AUTH_COMMAND authCommand = { 0 }; ++ grub_err_t err; ++ ++ if (!args->tpm2_evict) ++ { ++ printf (_("--tpm2-evict not specified, nothing to do.\n")); ++ return GRUB_ERR_NONE; ++ } ++ ++ err = grub_protect_tpm2_open_device (args->tpm2_device); ++ if (err) ++ return err; ++ ++ /* Find SRK */ ++ rc = TPM2_ReadPublic (args->tpm2_srk, NULL, &public); ++ if (rc != TPM_RC_SUCCESS) ++ { ++ fprintf (stderr, _("SRK with handle 0x%x not found.\n"), args->tpm2_srk); ++ err = GRUB_ERR_BAD_ARGUMENT; ++ goto exit1; ++ } ++ ++ /* Evict SRK */ ++ authCommand.sessionHandle = TPM_RS_PW; ++ ++ rc = TPM2_EvictControl (TPM_RH_OWNER, args->tpm2_srk, args->tpm2_srk, ++ &authCommand, NULL); ++ if (rc != TPM_RC_SUCCESS) ++ { ++ fprintf (stderr, ++ _("Failed to evict SRK with handle 0x%x (TPM Error: 0x%x).\n"), ++ args->tpm2_srk, rc); ++ err = GRUB_ERR_BAD_DEVICE; ++ goto exit2; ++ } ++ ++ err = GRUB_ERR_NONE; ++ ++exit2: ++ TPM2_FlushContext (args->tpm2_srk); ++ ++exit1: ++ grub_protect_tpm2_close_device (); ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_protect_tpm2_run (struct grub_protect_args *args) ++{ ++ switch (args->action) ++ { ++ case GRUB_PROTECT_ACTION_ADD: ++ return grub_protect_tpm2_add (args); ++ ++ case GRUB_PROTECT_ACTION_REMOVE: ++ return grub_protect_tpm2_remove (args); ++ ++ default: ++ return GRUB_ERR_BAD_ARGUMENT; ++ } ++} ++ ++static grub_err_t ++grub_protect_tpm2_args_verify (struct grub_protect_args *args) ++{ ++ switch (args->action) ++ { ++ case GRUB_PROTECT_ACTION_ADD: ++ if (args->args & GRUB_PROTECT_ARG_TPM2_EVICT) ++ { ++ fprintf (stderr, ++ _("--tpm2-evict is invalid when --action is 'add'.\n")); ++ return GRUB_ERR_BAD_ARGUMENT; ++ } ++ ++ if (!args->tpm2_keyfile) ++ { ++ fprintf (stderr, _("--tpm2-keyfile must be specified.\n")); ++ return GRUB_ERR_BAD_ARGUMENT; ++ } ++ ++ if (!args->tpm2_outfile) ++ { ++ fprintf (stderr, _("--tpm2-outfile must be specified.\n")); ++ return GRUB_ERR_BAD_ARGUMENT; ++ } ++ ++ if (!args->tpm2_device) ++ args->tpm2_device = "/dev/tpm0"; ++ ++ if (!args->tpm2_pcr_count) ++ { ++ args->tpm2_pcrs[0] = 7; ++ args->tpm2_pcr_count = 1; ++ } ++ ++ if (!args->tpm2_srk) ++ args->tpm2_srk = TPM2_SRK_HANDLE; ++ ++ if (!args->tpm2_asymmetric) ++ args->tpm2_asymmetric = TPM_ALG_RSA; ++ ++ if (!args->tpm2_bank) ++ args->tpm2_bank = TPM_ALG_SHA256; ++ ++ break; ++ ++ case GRUB_PROTECT_ACTION_REMOVE: ++ if (args->args & GRUB_PROTECT_ARG_TPM2_ASYMMETRIC) ++ { ++ fprintf (stderr, ++ _("--tpm2-asymmetric is invalid when --action is 'remove'.\n")); ++ return GRUB_ERR_BAD_ARGUMENT; ++ } ++ ++ if (args->args & GRUB_PROTECT_ARG_TPM2_BANK) ++ { ++ fprintf (stderr, ++ _("--tpm2-bank is invalid when --action is 'remove'.\n")); ++ return GRUB_ERR_BAD_ARGUMENT; ++ } ++ ++ if (args->args & GRUB_PROTECT_ARG_TPM2_KEYFILE) ++ { ++ fprintf (stderr, ++ _("--tpm2-keyfile is invalid when --action is 'remove'.\n")); ++ return GRUB_ERR_BAD_ARGUMENT; ++ } ++ ++ if (args->args & GRUB_PROTECT_ARG_TPM2_OUTFILE) ++ { ++ fprintf (stderr, ++ _("--tpm2-outfile is invalid when --action is 'remove'.\n")); ++ return GRUB_ERR_BAD_ARGUMENT; ++ } ++ ++ if (args->args & GRUB_PROTECT_ARG_TPM2_PCRS) ++ { ++ fprintf (stderr, ++ _("--tpm2-pcrs is invalid when --action is 'remove'.\n")); ++ return GRUB_ERR_BAD_ARGUMENT; ++ } ++ ++ if (args->args & GRUB_PROTECT_ARG_TPM2_PERSIST) ++ { ++ fprintf (stderr, ++ _("--tpm2-persist is invalid when --action is 'remove'.\n")); ++ return GRUB_ERR_BAD_ARGUMENT; ++ } ++ ++ if (!args->tpm2_device) ++ args->tpm2_device = "/dev/tpm0"; ++ ++ if (!args->tpm2_srk) ++ args->tpm2_srk = TPM2_SRK_HANDLE; ++ ++ break; ++ ++ default: ++ fprintf (stderr, ++ _("The TPM2 key protector only supports the following actions: " ++ "add, remove.\n")); ++ return GRUB_ERR_BAD_ARGUMENT; ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ ++static error_t ++grub_protect_argp_parser (int key, char *arg, struct argp_state *state) ++{ ++ grub_err_t err; ++ struct grub_protect_args *args = state->input; ++ ++ switch (key) ++ { ++ case GRUB_PROTECT_OPT_ACTION: ++ if (args->args & GRUB_PROTECT_ARG_ACTION) ++ { ++ fprintf (stderr, _("--action|-a can only be specified once.\n")); ++ return EINVAL; ++ } ++ ++ if (grub_strcmp (arg, "add") == 0) ++ args->action = GRUB_PROTECT_ACTION_ADD; ++ else if (grub_strcmp (arg, "remove") == 0) ++ args->action = GRUB_PROTECT_ACTION_REMOVE; ++ else ++ { ++ fprintf (stderr, _("'%s' is not a valid action.\n"), arg); ++ return EINVAL; ++ } ++ ++ args->args |= GRUB_PROTECT_ARG_ACTION; ++ break; ++ ++ case GRUB_PROTECT_OPT_PROTECTOR: ++ if (args->args & GRUB_PROTECT_ARG_PROTECTOR) ++ { ++ fprintf (stderr, _("--protector|-p can only be specified once.\n")); ++ return EINVAL; ++ } ++ ++ if (grub_strcmp (arg, "tpm2") == 0) ++ args->protector = GRUB_PROTECT_TYPE_TPM2; ++ else ++ { ++ fprintf (stderr, _("'%s' is not a valid protector.\n"), arg); ++ return EINVAL; ++ } ++ ++ args->args |= GRUB_PROTECT_ARG_PROTECTOR; ++ break; ++ ++ case GRUB_PROTECT_OPT_TPM2_DEVICE: ++ if (args->args & GRUB_PROTECT_ARG_TPM2_DEVICE) ++ { ++ fprintf (stderr, _("--tpm2-device can only be specified once.\n")); ++ return EINVAL; ++ } ++ ++ args->tpm2_device = xstrdup(arg); ++ args->args |= GRUB_PROTECT_ARG_TPM2_DEVICE; ++ break; ++ ++ case GRUB_PROTECT_OPT_TPM2_PCRS: ++ if (args->args & GRUB_PROTECT_ARG_TPM2_PCRS) ++ { ++ fprintf (stderr, _("--tpm2-pcrs can only be specified once.\n")); ++ return EINVAL; ++ } ++ ++ err = grub_tpm2_protector_parse_pcrs (arg, args->tpm2_pcrs, ++ &args->tpm2_pcr_count); ++ if (err) ++ { ++ if (grub_errno) ++ grub_print_error (); ++ return EINVAL; ++ } ++ ++ args->args |= GRUB_PROTECT_ARG_TPM2_PCRS; ++ break; ++ ++ case GRUB_PROTECT_OPT_TPM2_SRK: ++ if (args->args & GRUB_PROTECT_ARG_TPM2_SRK) ++ { ++ fprintf (stderr, _("--tpm2-srk can only be specified once.\n")); ++ return EINVAL; ++ } ++ ++ err = grub_tpm2_protector_parse_tpm_handle (arg, &args->tpm2_srk); ++ if (err) ++ { ++ if (grub_errno) ++ grub_print_error (); ++ return EINVAL; ++ } ++ ++ args->args |= GRUB_PROTECT_ARG_TPM2_SRK; ++ break; ++ ++ case GRUB_PROTECT_OPT_TPM2_ASYMMETRIC: ++ if (args->args & GRUB_PROTECT_ARG_TPM2_ASYMMETRIC) ++ { ++ fprintf (stderr, _("--tpm2-asymmetric can only be specified once.\n")); ++ return EINVAL; ++ } ++ ++ err = grub_tpm2_protector_parse_asymmetric (arg, &args->tpm2_asymmetric); ++ if (err) ++ { ++ if (grub_errno) ++ grub_print_error (); ++ return EINVAL; ++ } ++ ++ args->args |= GRUB_PROTECT_ARG_TPM2_ASYMMETRIC; ++ break; ++ ++ case GRUB_PROTECT_OPT_TPM2_BANK: ++ if (args->args & GRUB_PROTECT_ARG_TPM2_BANK) ++ { ++ fprintf (stderr, _("--tpm2-bank can only be specified once.\n")); ++ return EINVAL; ++ } ++ ++ err = grub_tpm2_protector_parse_bank (arg, &args->tpm2_bank); ++ if (err) ++ { ++ if (grub_errno) ++ grub_print_error (); ++ return EINVAL; ++ } ++ ++ args->args |= GRUB_PROTECT_ARG_TPM2_BANK; ++ break; ++ ++ case GRUB_PROTECT_OPT_TPM2_KEYFILE: ++ if (args->args & GRUB_PROTECT_ARG_TPM2_KEYFILE) ++ { ++ fprintf (stderr, _("--tpm2-keyfile can only be specified once.\n")); ++ return EINVAL; ++ } ++ ++ args->tpm2_keyfile = xstrdup(arg); ++ args->args |= GRUB_PROTECT_ARG_TPM2_KEYFILE; ++ break; ++ ++ case GRUB_PROTECT_OPT_TPM2_OUTFILE: ++ if (args->args & GRUB_PROTECT_ARG_TPM2_OUTFILE) ++ { ++ fprintf (stderr, _("--tpm2-outfile can only be specified once.\n")); ++ return EINVAL; ++ } ++ ++ args->tpm2_outfile = xstrdup(arg); ++ args->args |= GRUB_PROTECT_ARG_TPM2_OUTFILE; ++ break; ++ ++ case GRUB_PROTECT_OPT_TPM2_PERSIST: ++ if (args->args & GRUB_PROTECT_ARG_TPM2_PERSIST) ++ { ++ fprintf (stderr, _("--tpm2-persist can only be specified once.\n")); ++ return EINVAL; ++ } ++ ++ args->tpm2_persist = 1; ++ args->args |= GRUB_PROTECT_ARG_TPM2_PERSIST; ++ break; ++ ++ case GRUB_PROTECT_OPT_TPM2_EVICT: ++ if (args->args & GRUB_PROTECT_ARG_TPM2_EVICT) ++ { ++ fprintf (stderr, _("--tpm2-evict can only be specified once.\n")); ++ return EINVAL; ++ } ++ ++ args->tpm2_evict = 1; ++ args->args |= GRUB_PROTECT_ARG_TPM2_EVICT; ++ break; ++ ++ default: ++ return ARGP_ERR_UNKNOWN; ++ } ++ ++ return 0; ++} ++ ++static grub_err_t ++grub_protect_args_verify (struct grub_protect_args *args) ++{ ++ if (args->action == GRUB_PROTECT_ACTION_ERROR) ++ { ++ fprintf (stderr, "--action is mandatory.\n"); ++ return GRUB_ERR_BAD_ARGUMENT; ++ } ++ ++ /* At the moment, the only configurable key protector is the TPM2 one, so it ++ * is the only key protector supported by this tool. */ ++ if (args->protector != GRUB_PROTECT_TYPE_TPM2) ++ { ++ fprintf (stderr, ++ _("--protector is mandatory and only 'tpm2' is currently " ++ "supported.\n")); ++ return GRUB_ERR_BAD_ARGUMENT; ++ } ++ ++ switch (args->protector) ++ { ++ case GRUB_PROTECT_TYPE_TPM2: ++ return grub_protect_tpm2_args_verify (args); ++ default: ++ return GRUB_ERR_BAD_ARGUMENT; ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_protect_dispatch (struct grub_protect_args *args) ++{ ++ switch (args->protector) ++ { ++ case GRUB_PROTECT_TYPE_TPM2: ++ return grub_protect_tpm2_run (args); ++ default: ++ return GRUB_ERR_BAD_ARGUMENT; ++ } ++} ++ ++static void ++grub_protect_init (int *argc, char **argv[]) ++{ ++ grub_util_host_init (argc, argv); ++ ++ grub_util_biosdisk_init (NULL); ++ ++ grub_init_all (); ++ grub_gcry_init_all (); ++ ++ grub_lvm_fini (); ++ grub_mdraid09_fini (); ++ grub_mdraid1x_fini (); ++ grub_diskfilter_fini (); ++ grub_diskfilter_init (); ++ grub_mdraid09_init (); ++ grub_mdraid1x_init (); ++ grub_lvm_init (); ++} ++ ++static void ++grub_protect_fini (void) ++{ ++ grub_gcry_fini_all (); ++ grub_fini_all (); ++ grub_util_biosdisk_fini (); ++} ++ ++static struct argp grub_protect_argp = ++{ ++ .options = grub_protect_options, ++ .parser = grub_protect_argp_parser, ++ .args_doc = NULL, ++ .doc = ++ N_("Protect a cleartext key using a GRUB key protector that can retrieve " ++ "the key during boot to unlock fully-encrypted disks automatically."), ++ .children = NULL, ++ .help_filter = NULL, ++ .argp_domain = NULL ++}; ++ ++int ++main (int argc, char *argv[]) ++{ ++ grub_err_t err; ++ struct grub_protect_args args = { 0 }; ++ ++ if (argp_parse (&grub_protect_argp, argc, argv, 0, 0, &args) != 0) ++ { ++ fprintf (stderr, _("Could not parse arguments.\n")); ++ return GRUB_ERR_BAD_ARGUMENT; ++ } ++ ++ grub_protect_init (&argc, &argv); ++ ++ err = grub_protect_args_verify (&args); ++ if (err) ++ goto exit; ++ ++ err = grub_protect_dispatch (&args); ++ if (err) ++ goto exit; ++ ++exit: ++ grub_protect_fini (); ++ ++ return err; ++} +-- +2.34.1 + diff --git a/fix-tpm2-build.patch b/fix-tpm2-build.patch new file mode 100644 index 0000000..2a4fc24 --- /dev/null +++ b/fix-tpm2-build.patch @@ -0,0 +1,38 @@ +--- + grub-core/Makefile.core.def | 1 + + grub-core/tpm2/module.c | 2 +- + util/grub-protect.c | 2 +- + 3 files changed, 3 insertions(+), 2 deletions(-) + +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -2569,6 +2569,7 @@ + common = tpm2/mu.c; + common = tpm2/tpm2.c; + efi = tpm2/tcg2.c; ++ enable = efi; + }; + + module = { +--- a/util/grub-protect.c ++++ b/util/grub-protect.c +@@ -542,7 +542,7 @@ + if (pcr_values.digests[i].size != pcr_digest_len) + { + fprintf (stderr, +- _("Bad PCR value size: expected %lu bytes but got %u bytes.\n"), ++ _("Bad PCR value size: expected %" PRIuGRUB_SIZE " bytes but got %u bytes.\n"), + pcr_digest_len, pcr_values.digests[i].size); + goto exit2; + } +--- a/grub-core/tpm2/module.c ++++ b/grub-core/tpm2/module.c +@@ -195,7 +195,7 @@ + if (sealed_key_size > buf.cap) + { + grub_dprintf ("tpm2", "Sealed key file is larger than decode buffer " +- "(%lu vs %lu bytes).\n", sealed_key_size, buf.cap); ++ "(%" PRIuGRUB_SIZE " vs %" PRIuGRUB_SIZE " bytes).\n", sealed_key_size, buf.cap); + return GRUB_ERR_BAD_ARGUMENT; + } + diff --git a/grub2.changes b/grub2.changes index c7b5a0f..09d3f17 100644 --- a/grub2.changes +++ b/grub2.changes @@ -1,3 +1,37 @@ +------------------------------------------------------------------- +Wed Jun 8 03:25:26 UTC 2022 - Michael Chang + +- Add tpm, tpm2, luks2 and gcry_sha512 to default grub.efi (bsc#1197625) +- Make grub-tpm.efi a symlink to grub.efi + * grub2.spec +- Log error when tpm event log is full and continue + * 0001-tpm-Log-EFI_VOLUME_FULL-and-continue.patch +- Patch superseded + * 0001-tpm-Pass-unknown-error-as-non-fatal-but-debug-print-.patch + +------------------------------------------------------------------- +Wed Jun 8 03:17:29 UTC 2022 - Michael Chang + +- Add patches for automatic TPM disk unlock (jsc#SLE-24018) (bsc#1196668) + * 0001-luks2-Add-debug-message-to-align-with-luks-and-geli-.patch + * 0002-cryptodisk-Refactor-to-discard-have_it-global.patch + * 0003-cryptodisk-Return-failure-in-cryptomount-when-no-cry.patch + * 0004-cryptodisk-Improve-error-messaging-in-cryptomount-in.patch + * 0005-cryptodisk-Improve-cryptomount-u-error-message.patch + * 0006-cryptodisk-Add-infrastructure-to-pass-data-from-cryp.patch + * 0007-cryptodisk-Refactor-password-input-out-of-crypto-dev.patch + * 0008-cryptodisk-Move-global-variables-into-grub_cryptomou.patch + * 0009-cryptodisk-Improve-handling-of-partition-name-in-cry.patch + * 0010-protectors-Add-key-protectors-framework.patch + * 0011-tpm2-Add-TPM-Software-Stack-TSS.patch + * 0012-protectors-Add-TPM2-Key-Protector.patch + * 0013-cryptodisk-Support-key-protectors.patch + * 0014-util-grub-protect-Add-new-tool.patch +- Fix no disk unlocking happen (bsc#1196668) + * 0001-crytodisk-fix-cryptodisk-module-looking-up.patch +- Fix build error + * fix-tpm2-build.patch + ------------------------------------------------------------------- Tue May 31 04:44:18 UTC 2022 - Michael Chang diff --git a/grub2.spec b/grub2.spec index 613adb7..bde1da4 100644 --- a/grub2.spec +++ b/grub2.spec @@ -315,7 +315,6 @@ Patch789: 0001-Workaround-volatile-efi-boot-variable.patch Patch790: 0001-30_uefi-firmware-fix-printf-format-with-null-byte.patch Patch791: 0001-i386-pc-build-btrfs-zstd-support-into-separate-modul.patch Patch792: 0001-templates-Follow-the-path-of-usr-merged-kernel-confi.patch -Patch793: 0001-tpm-Pass-unknown-error-as-non-fatal-but-debug-print-.patch Patch794: 0001-Filter-out-POSIX-locale-for-translation.patch Patch795: 0001-ieee1275-implement-FCP-methods-for-WWPN-and-LUNs.patch Patch796: 0001-disk-diskfilter-Use-nodes-in-logical-volume-s-segmen.patch @@ -407,6 +406,23 @@ Patch881: 0029-fs-btrfs-Fix-several-fuzz-issues-with-invalid-dir-it.patch Patch882: 0030-fs-btrfs-Fix-more-ASAN-and-SEGV-issues-found-with-fu.patch Patch883: 0031-fs-btrfs-Fix-more-fuzz-issues-related-to-chunks.patch Patch884: 0032-Use-grub_loader_set_ex-for-secureboot-chainloader.patch +Patch885: 0001-luks2-Add-debug-message-to-align-with-luks-and-geli-.patch +Patch886: 0002-cryptodisk-Refactor-to-discard-have_it-global.patch +Patch887: 0003-cryptodisk-Return-failure-in-cryptomount-when-no-cry.patch +Patch888: 0004-cryptodisk-Improve-error-messaging-in-cryptomount-in.patch +Patch889: 0005-cryptodisk-Improve-cryptomount-u-error-message.patch +Patch890: 0006-cryptodisk-Add-infrastructure-to-pass-data-from-cryp.patch +Patch891: 0007-cryptodisk-Refactor-password-input-out-of-crypto-dev.patch +Patch892: 0008-cryptodisk-Move-global-variables-into-grub_cryptomou.patch +Patch893: 0009-cryptodisk-Improve-handling-of-partition-name-in-cry.patch +Patch894: 0010-protectors-Add-key-protectors-framework.patch +Patch895: 0011-tpm2-Add-TPM-Software-Stack-TSS.patch +Patch896: 0012-protectors-Add-TPM2-Key-Protector.patch +Patch897: 0013-cryptodisk-Support-key-protectors.patch +Patch898: 0014-util-grub-protect-Add-new-tool.patch +Patch899: fix-tpm2-build.patch +Patch900: 0001-crytodisk-fix-cryptodisk-module-looking-up.patch +Patch901: 0001-tpm-Log-EFI_VOLUME_FULL-and-continue.patch Requires: gettext-runtime %if 0%{?suse_version} >= 1140 @@ -675,9 +691,9 @@ CD_MODULES="all_video boot cat configfile echo true \ password password_pbkdf2 png reboot search search_fs_uuid \ search_fs_file search_label sleep test video fat loadenv" PXE_MODULES="tftp http" -CRYPTO_MODULES="luks gcry_rijndael gcry_sha1 gcry_sha256" +CRYPTO_MODULES="luks luks2 gcry_rijndael gcry_sha1 gcry_sha256 gcry_sha512" %ifarch %{efi} -CD_MODULES="${CD_MODULES} chain efifwsetup efinet read" +CD_MODULES="${CD_MODULES} chain efifwsetup efinet read tpm tpm2" PXE_MODULES="${PXE_MODULES} efinet" %else CD_MODULES="${CD_MODULES} net" @@ -715,10 +731,6 @@ echo "grub.%{sbat_distro},%{sbat_generation},%{sbat_distro_summary},%{name},%{ve ./grub-mkimage -O %{grubefiarch} -o grub.efi --prefix= %{?sbat_generation:--sbat sbat.csv} \ -d grub-core ${GRUB_MODULES} -%ifarch x86_64 -./grub-mkimage -O %{grubefiarch} -o grub-tpm.efi --prefix= %{?sbat_generation:--sbat sbat.csv} \ - -d grub-core ${GRUB_MODULES} tpm -%endif %ifarch x86_64 aarch64 if test -e %{_sourcedir}/_projectcert.crt ; then @@ -898,7 +910,7 @@ cd build-efi %make_install install -m 644 grub.efi %{buildroot}/%{_datadir}/%{name}/%{grubefiarch}/. %ifarch x86_64 -install -m 644 grub-tpm.efi %{buildroot}/%{_datadir}/%{name}/%{grubefiarch}/. +ln -srf %{buildroot}/%{_datadir}/%{name}/%{grubefiarch}/grub.efi %{buildroot}/%{_datadir}/%{name}/%{grubefiarch}/grub-tpm.efi %endif # Create grub.efi link to system efi directory @@ -920,9 +932,6 @@ EoM %ifarch x86_64 aarch64 export BRP_PESIGN_FILES="%{_datadir}/%{name}/%{grubefiarch}/grub.efi" -%ifarch x86_64 -BRP_PESIGN_FILES="${BRP_PESIGN_FILES} %{_datadir}/%{name}/%{grubefiarch}/grub-tpm.efi" -%endif install -m 444 grub.der %{buildroot}/%{sysefidir}/ %endif @@ -1249,6 +1258,7 @@ fi %{_bindir}/%{name}-render-label %{_bindir}/%{name}-script-check %{_bindir}/%{name}-syslinux2cfg +%{_bindir}/%{name}-protect %if 0%{?has_systemd:1} %{_unitdir}/grub2-once.service %endif