diff --git a/0001-commands-efi-tpm-Refine-the-status-of-log-event.patch b/0001-commands-efi-tpm-Refine-the-status-of-log-event.patch new file mode 100644 index 0000000..c284274 --- /dev/null +++ b/0001-commands-efi-tpm-Refine-the-status-of-log-event.patch @@ -0,0 +1,39 @@ +From d2c0426b3f0f91b941037263c83859a46ebb0c4f Mon Sep 17 00:00:00 2001 +From: Lu Ken +Date: Wed, 13 Jul 2022 10:06:10 +0800 +Subject: [PATCH 1/3] commands/efi/tpm: Refine the status of log event + +1. Use macro GRUB_ERR_NONE instead of hard code 0. +2. Keep lowercase of the first char for the status string of log event. + +Signed-off-by: Lu Ken +Reviewed-by: Daniel Kiper +--- + grub-core/commands/efi/tpm.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/grub-core/commands/efi/tpm.c b/grub-core/commands/efi/tpm.c +index f296b8698..19737b462 100644 +--- a/grub-core/commands/efi/tpm.c ++++ b/grub-core/commands/efi/tpm.c +@@ -136,13 +136,13 @@ grub_efi_log_event_status (grub_efi_status_t status) + switch (status) + { + case GRUB_EFI_SUCCESS: +- return 0; ++ return GRUB_ERR_NONE; + case GRUB_EFI_DEVICE_ERROR: +- return grub_error (GRUB_ERR_IO, N_("Command failed")); ++ return grub_error (GRUB_ERR_IO, N_("command failed")); + case GRUB_EFI_INVALID_PARAMETER: +- return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Invalid parameter")); ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("invalid parameter")); + case GRUB_EFI_BUFFER_TOO_SMALL: +- return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Output buffer too small")); ++ 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")); + default: +-- +2.35.3 + 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-devmapper-getroot-Have-devmapper-recognize-LUKS2.patch b/0001-devmapper-getroot-Have-devmapper-recognize-LUKS2.patch new file mode 100644 index 0000000..268417a --- /dev/null +++ b/0001-devmapper-getroot-Have-devmapper-recognize-LUKS2.patch @@ -0,0 +1,53 @@ +From ebe4ac49e800b18b539564169593ab1c6f163378 Mon Sep 17 00:00:00 2001 +From: Josselin Poiret via Grub-devel +Date: Tue, 14 Jun 2022 15:47:29 +0200 +Subject: [PATCH 01/10] devmapper/getroot: Have devmapper recognize LUKS2 + +Changes UUID comparisons so that LUKS1 and LUKS2 are both recognized +as being LUKS cryptodisks. +--- + grub-core/osdep/devmapper/getroot.c | 11 +++++++---- + 1 file changed, 7 insertions(+), 4 deletions(-) + +diff --git a/grub-core/osdep/devmapper/getroot.c b/grub-core/osdep/devmapper/getroot.c +index 9ba5c98655..2bf4264cf0 100644 +--- a/grub-core/osdep/devmapper/getroot.c ++++ b/grub-core/osdep/devmapper/getroot.c +@@ -138,7 +138,8 @@ grub_util_get_dm_abstraction (const char *os_dev) + grub_free (uuid); + return GRUB_DEV_ABSTRACTION_LVM; + } +- if (strncmp (uuid, "CRYPT-LUKS1-", 12) == 0) ++ if (strncmp (uuid, "CRYPT-LUKS1-", sizeof ("CRYPT-LUKS1-") - 1) == 0 ++ || strncmp (uuid, "CRYPT-LUKS2-", sizeof ("CRYPT-LUKS2-") - 1) == 0) + { + grub_free (uuid); + return GRUB_DEV_ABSTRACTION_LUKS; +@@ -179,7 +180,9 @@ grub_util_pull_devmapper (const char *os_dev) + grub_util_pull_device (subdev); + } + } +- if (uuid && strncmp (uuid, "CRYPT-LUKS1-", sizeof ("CRYPT-LUKS1-") - 1) == 0 ++ if (uuid ++ && (strncmp (uuid, "CRYPT-LUKS1-", sizeof ("CRYPT-LUKS1-") - 1) == 0 ++ || strncmp (uuid, "CRYPT-LUKS2-", sizeof ("CRYPT-LUKS2-") - 1) == 0) + && lastsubdev) + { + char *grdev = grub_util_get_grub_dev (lastsubdev); +@@ -253,11 +256,11 @@ grub_util_get_devmapper_grub_dev (const char *os_dev) + { + char *dash; + +- dash = grub_strchr (uuid + sizeof ("CRYPT-LUKS1-") - 1, '-'); ++ dash = grub_strchr (uuid + sizeof ("CRYPT-LUKS*-") - 1, '-'); + if (dash) + *dash = 0; + grub_dev = grub_xasprintf ("cryptouuid/%s", +- uuid + sizeof ("CRYPT-LUKS1-") - 1); ++ uuid + sizeof ("CRYPT-LUKS*-") - 1); + grub_free (uuid); + return grub_dev; + } +-- +2.34.1 + diff --git a/0001-grub-install-set-point-of-no-return-for-powerpc-ieee1275.patch b/0001-grub-install-set-point-of-no-return-for-powerpc-ieee1275.patch new file mode 100644 index 0000000..47696be --- /dev/null +++ b/0001-grub-install-set-point-of-no-return-for-powerpc-ieee1275.patch @@ -0,0 +1,32 @@ +From grub-devel-bounces@gnu.org Thu Aug 25 08:11:08 2022 +From: Michael Chang +Date: Thu, 25 Aug 2022 14:05:01 +0800 +Subject: [PATCH] grub-install: set point of no return for powerpc-ieee1275 + install + +The point of no return is used to define a point where no change should +be reverted in a wake of fatal error that consequently aborts the +process. The powerpc-ieee1275 install apparently missed this point of no +return defintion that newly installed modules could be inadvertently +reverted after successful image embedding so that boot failure is +incurred due to inconsistent state. + +Signed-off-by: Michael Chang +[iluceno@suse.de: Backported to SLES-15-SP4] +Signed-off-by: Ismael Luceno +--- + util/grub-install.c | 1 + + 1 file changed, 1 insertion(+) + +Index: grub-2.06/util/grub-install.c +=================================================================== +--- grub-2.06.orig/util/grub-install.c ++++ grub-2.06/util/grub-install.c +@@ -2160,6 +2160,7 @@ main (int argc, char *argv[]) + { + grub_util_error ("%s", _("failed to copy Grub to the PReP partition")); + } ++ grub_set_install_backup_ponr (); + + if ((signed_grub_mode >= SIGNED_GRUB_FORCE) || ((signed_grub_mode == SIGNED_GRUB_AUTO) && (ppc_sb_state > 0))) + { diff --git a/0001-ibmvtpm-Add-support-for-trusted-boot-using-a-vTPM-2..patch b/0001-ibmvtpm-Add-support-for-trusted-boot-using-a-vTPM-2..patch new file mode 100644 index 0000000..f3f26ea --- /dev/null +++ b/0001-ibmvtpm-Add-support-for-trusted-boot-using-a-vTPM-2..patch @@ -0,0 +1,239 @@ +From f86bd28391e6d92f8084f0b789ba4a8f6d789dfa Mon Sep 17 00:00:00 2001 +From: Stefan Berger +Date: Sun, 15 Mar 2020 12:37:10 -0400 +Subject: [PATCH 1/2] ibmvtpm: Add support for trusted boot using a vTPM 2.0 + +Add support for trusted boot using a vTPM 2.0 on the IBM IEEE1275 +PowerPC platform. With this patch grub now measures text and binary data +into the TPM's PCRs 8 and 9 in the same way as the x86_64 platform +does. + +This patch requires Daniel Axtens's patches for claiming more memory. + +For vTPM support to work on PowerVM, system driver levels 1010.30 +or 1020.00 are required. + +Note: Previous versions of firmware levels with the 2hash-ext-log +API call have a bug that, once this API call is invoked, has the +effect of disabling the vTPM driver under Linux causing an error +message to be displayed in the Linux kernel log. Those users will +have to update their machines to the firmware levels mentioned +above. + +Cc: Eric Snowberg +Signed-off-by: Stefan Berger +--- + docs/grub.texi | 3 +- + grub-core/Makefile.core.def | 7 ++ + grub-core/commands/ieee1275/ibmvtpm.c | 152 ++++++++++++++++++++++++++ + include/grub/ieee1275/ieee1275.h | 3 + + 4 files changed, 164 insertions(+), 1 deletion(-) + create mode 100644 grub-core/commands/ieee1275/ibmvtpm.c + +diff --git a/docs/grub.texi b/docs/grub.texi +index 4504bcabe..026aacacf 100644 +--- a/docs/grub.texi ++++ b/docs/grub.texi +@@ -6204,7 +6204,8 @@ tpm module is loaded. As such it is recommended that the tpm module be built + into @file{core.img} in order to avoid a potential gap in measurement between + @file{core.img} being loaded and the tpm module being loaded. + +-Measured boot is currently only supported on EFI platforms. ++Measured boot is currently only supported on EFI and IBM IEEE1275 PowerPC ++platforms. + + @node Lockdown + @section Lockdown when booting on a secure setup +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index cee596872..54733425c 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -1141,6 +1141,13 @@ module = { + enable = powerpc_ieee1275; + }; + ++module = { ++ name = tpm; ++ common = commands/tpm.c; ++ ieee1275 = commands/ieee1275/ibmvtpm.c; ++ enable = powerpc_ieee1275; ++}; ++ + module = { + name = terminal; + common = commands/terminal.c; +diff --git a/grub-core/commands/ieee1275/ibmvtpm.c b/grub-core/commands/ieee1275/ibmvtpm.c +new file mode 100644 +index 000000000..e68b8448b +--- /dev/null ++++ b/grub-core/commands/ieee1275/ibmvtpm.c +@@ -0,0 +1,152 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2021 Free Software Foundation, Inc. ++ * Copyright (C) 2021 IBM 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 . ++ * ++ * IBM vTPM support code. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static grub_ieee1275_ihandle_t tpm_ihandle; ++static grub_uint8_t tpm_version; ++ ++#define IEEE1275_IHANDLE_INVALID ((grub_ieee1275_ihandle_t)0) ++ ++static void ++tpm_get_tpm_version (void) ++{ ++ grub_ieee1275_phandle_t vtpm; ++ char buffer[20]; ++ ++ if (!grub_ieee1275_finddevice ("/vdevice/vtpm", &vtpm) && ++ !grub_ieee1275_get_property (vtpm, "compatible", buffer, ++ sizeof (buffer), NULL) && ++ !grub_strcmp (buffer, "IBM,vtpm20")) ++ tpm_version = 2; ++} ++ ++static grub_err_t ++tpm_init (void) ++{ ++ static int init_success = 0; ++ ++ if (!init_success) ++ { ++ if (grub_ieee1275_open ("/vdevice/vtpm", &tpm_ihandle) < 0) { ++ tpm_ihandle = IEEE1275_IHANDLE_INVALID; ++ return GRUB_ERR_UNKNOWN_DEVICE; ++ } ++ ++ init_success = 1; ++ ++ tpm_get_tpm_version (); ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ ++static int ++ibmvtpm_2hash_ext_log (grub_uint8_t pcrindex, ++ grub_uint32_t eventtype, ++ const char *description, ++ grub_size_t description_size, ++ void *buf, grub_size_t size) ++{ ++ struct tpm_2hash_ext_log ++ { ++ struct grub_ieee1275_common_hdr common; ++ grub_ieee1275_cell_t method; ++ grub_ieee1275_cell_t ihandle; ++ grub_ieee1275_cell_t size; ++ grub_ieee1275_cell_t buf; ++ grub_ieee1275_cell_t description_size; ++ grub_ieee1275_cell_t description; ++ grub_ieee1275_cell_t eventtype; ++ grub_ieee1275_cell_t pcrindex; ++ grub_ieee1275_cell_t catch_result; ++ grub_ieee1275_cell_t rc; ++ } ++ args; ++ ++ INIT_IEEE1275_COMMON (&args.common, "call-method", 8, 2); ++ args.method = (grub_ieee1275_cell_t) "2hash-ext-log"; ++ args.ihandle = tpm_ihandle; ++ args.pcrindex = pcrindex; ++ args.eventtype = eventtype; ++ args.description = (grub_ieee1275_cell_t) description; ++ args.description_size = description_size; ++ args.buf = (grub_ieee1275_cell_t) buf; ++ args.size = (grub_ieee1275_cell_t) size; ++ ++ if (IEEE1275_CALL_ENTRY_FN (&args) == -1) ++ return -1; ++ ++ /* ++ * catch_result is set if firmware does not support 2hash-ext-log ++ * rc is GRUB_IEEE1275_CELL_FALSE (0) on failure ++ */ ++ if ((args.catch_result) || args.rc == GRUB_IEEE1275_CELL_FALSE) ++ return -1; ++ ++ return 0; ++} ++ ++static grub_err_t ++tpm2_log_event (unsigned char *buf, ++ grub_size_t size, grub_uint8_t pcr, ++ const char *description) ++{ ++ static int error_displayed = 0; ++ int err; ++ ++ err = ibmvtpm_2hash_ext_log (pcr, EV_IPL, ++ description, ++ grub_strlen(description) + 1, ++ buf, size); ++ if (err && !error_displayed) ++ { ++ error_displayed++; ++ return grub_error (GRUB_ERR_BAD_DEVICE, ++ "2HASH-EXT-LOG failed: Firmware is likely too old.\n"); ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ ++grub_err_t ++grub_tpm_measure (unsigned char *buf, grub_size_t size, grub_uint8_t pcr, ++ const char *description) ++{ ++ grub_err_t err = tpm_init(); ++ ++ /* Absence of a TPM isn't a failure. */ ++ if (err != GRUB_ERR_NONE) ++ return GRUB_ERR_NONE; ++ ++ grub_dprintf ("tpm", "log_event, pcr = %d, size = 0x%" PRIxGRUB_SIZE ", %s\n", ++ pcr, size, description); ++ ++ if (tpm_version == 2) ++ return tpm2_log_event (buf, size, pcr, description); ++ ++ return GRUB_ERR_NONE; ++} +diff --git a/include/grub/ieee1275/ieee1275.h b/include/grub/ieee1275/ieee1275.h +index 591f4f12c..8a621af7c 100644 +--- a/include/grub/ieee1275/ieee1275.h ++++ b/include/grub/ieee1275/ieee1275.h +@@ -24,6 +24,9 @@ + #include + #include + ++#define GRUB_IEEE1275_CELL_FALSE ((grub_ieee1275_cell_t) 0) ++#define GRUB_IEEE1275_CELL_TRUE ((grub_ieee1275_cell_t) -1) ++ + struct grub_ieee1275_mem_region + { + unsigned int start; +-- +2.35.3 + diff --git a/0001-ieee1275-add-support-for-NVMeoFC.patch b/0001-ieee1275-add-support-for-NVMeoFC.patch new file mode 100644 index 0000000..f9cbc98 --- /dev/null +++ b/0001-ieee1275-add-support-for-NVMeoFC.patch @@ -0,0 +1,250 @@ +From c125cb45a7885d7bf168a05cfa4da3e681244649 Mon Sep 17 00:00:00 2001 +From: Diego Domingos +Date: Tue, 15 Feb 2022 13:11:48 -0500 +Subject: [PATCH 1/4] ieee1275: add support for NVMeoFC + +Implements the functions to scan and discovery of NVMeoFC. +--- + grub-core/disk/ieee1275/ofdisk.c | 217 ++++++++++++++++++++++++++++++- + 1 file changed, 213 insertions(+), 4 deletions(-) + +diff --git a/grub-core/disk/ieee1275/ofdisk.c b/grub-core/disk/ieee1275/ofdisk.c +index 410f4b849..852bb95be 100644 +--- a/grub-core/disk/ieee1275/ofdisk.c ++++ b/grub-core/disk/ieee1275/ofdisk.c +@@ -206,12 +206,10 @@ dev_iterate_real (const char *name, const char *path) + return; + } + ++ + static void +-dev_iterate (const struct grub_ieee1275_devalias *alias) ++dev_iterate_fcp_disks(const struct grub_ieee1275_devalias *alias) + { +- if (grub_strcmp (alias->type, "fcp") == 0) +- { +- + /* If we are dealing with fcp devices, we need + * to find the WWPNs and LUNs to iterate them */ + grub_ieee1275_ihandle_t ihandle; +@@ -323,6 +321,217 @@ dev_iterate (const struct grub_ieee1275_devalias *alias) + grub_free (buf); + return; + ++} ++ ++static void ++dev_iterate_fcp_nvmeof (const struct grub_ieee1275_devalias *alias) ++{ ++ ++ ++ char *bufptr; ++ grub_ieee1275_ihandle_t ihandle; ++ ++ ++ // Create the structs for the parameters passing to PFW ++ struct nvme_args_ ++ { ++ struct grub_ieee1275_common_hdr common; ++ grub_ieee1275_cell_t method; ++ grub_ieee1275_cell_t ihandle; ++ grub_ieee1275_cell_t catch_result; ++ grub_ieee1275_cell_t nentries; ++ grub_ieee1275_cell_t table; ++ } nvme_discovery_controllers_args, nvme_controllers_args, nvme_namespaces_args; ++ ++ ++ // Create the structs for the results from PFW ++ ++ struct discovery_controllers_table_struct_ ++ { ++ grub_uint64_t table[256]; ++ grub_uint32_t len; ++ } discovery_controllers_table; ++ ++ /* struct nvme_controllers_table_entry ++ * this the return of nvme-controllers method tables, containing: ++ * - 2-byte controller ID ++ * - 256-byte transport address string ++ * - 256-byte field containing null-terminated NVM subsystem NQN string up to 223 characters ++ */ ++ struct nvme_controllers_table_entry_ ++ { ++ grub_uint16_t id; ++ char wwpn[256]; ++ char nqn[256]; ++ }; ++ ++ struct nvme_controllers_table_entry_* nvme_controllers_table = grub_malloc(sizeof(struct nvme_controllers_table_entry_)*256); ++ ++ grub_uint32_t nvme_controllers_table_entries; ++ ++ struct nvme_controllers_table_entry_real ++ { ++ grub_uint16_t id; ++ char wwpn[256]; ++ char nqn[256]; ++ }; ++ ++ /* Allocate memory for building the NVMeoF path */ ++ char *buf = grub_malloc (grub_strlen (alias->path) + 512); ++ if (!buf) ++ { ++ grub_ieee1275_close(ihandle); ++ return; ++ } ++ ++ /* Copy the alias->path to buf so we can work with */ ++ bufptr = grub_stpcpy (buf, alias->path); ++ grub_snprintf (bufptr, 32, "/nvme-of"); ++ ++ /* ++ * Open the nvme-of layer ++ * Ex. /pci@bus/fibre-channel@@dev,func/nvme-of ++ */ ++ if(grub_ieee1275_open (buf, &ihandle)) ++ { ++ grub_dprintf("disk", "failed to open the disk while iterating FCP disk path=%s\n", buf); ++ return; ++ } ++ ++ /* ++ * Call to nvme-discovery-controllers method from the nvme-of layer ++ * to get a list of the NVMe discovery controllers per the binding ++ */ ++ ++ INIT_IEEE1275_COMMON (&nvme_discovery_controllers_args.common, "call-method", 2, 2); ++ nvme_discovery_controllers_args.method = (grub_ieee1275_cell_t) "nvme-discovery-controllers"; ++ nvme_discovery_controllers_args.ihandle = ihandle; ++ ++ if (IEEE1275_CALL_ENTRY_FN (&nvme_discovery_controllers_args) == -1) ++ { ++ grub_dprintf("disk", "failed to get the targets while iterating FCP disk path=%s\n", buf); ++ grub_ieee1275_close(ihandle); ++ return; ++ } ++ ++ /* After closing the device, the info is lost. So lets copy each buffer in the buffers table */ ++ ++ discovery_controllers_table.len = (grub_uint32_t) nvme_discovery_controllers_args.nentries; ++ ++ unsigned int i=0; ++ for(i = 0; i < discovery_controllers_table.len; i++){ ++ discovery_controllers_table.table[i] = ((grub_uint64_t*)nvme_discovery_controllers_args.table)[i]; ++ } ++ ++ grub_ieee1275_close(ihandle); ++ ++ grub_dprintf("ofdisk","NVMeoF: Found %d discovery controllers\n",discovery_controllers_table.len); ++ ++ /* For each nvme discovery controller */ ++ int current_buffer_index; ++ for(current_buffer_index = 0; current_buffer_index < (int) discovery_controllers_table.len; current_buffer_index++){ ++ ++ ++ grub_snprintf (bufptr, 64, "/nvme-of/controller@%" PRIxGRUB_UINT64_T ",ffff", ++ discovery_controllers_table.table[current_buffer_index]); ++ ++ grub_dprintf("ofdisk","nvmeof controller=%s\n",buf); ++ ++ if(grub_ieee1275_open (buf, &ihandle)) ++ { ++ grub_dprintf("ofdisk", "failed to open the disk while getting nvme-controllers path=%s\n", buf); ++ continue; ++ } ++ ++ ++ INIT_IEEE1275_COMMON (&nvme_controllers_args.common, "call-method", 2, 2); ++ nvme_controllers_args.method = (grub_ieee1275_cell_t) "nvme-controllers"; ++ nvme_controllers_args.ihandle = ihandle; ++ nvme_controllers_args.catch_result = 0; ++ ++ ++ if (IEEE1275_CALL_ENTRY_FN (&nvme_controllers_args) == -1) ++ { ++ grub_dprintf("ofdisk", "failed to get the nvme-controllers while iterating FCP disk path\n"); ++ grub_ieee1275_close(ihandle); ++ continue; ++ } ++ ++ ++ /* Copy the buffer list to nvme_controllers_table */ ++ nvme_controllers_table_entries = ((grub_uint32_t) nvme_controllers_args.nentries); ++ struct nvme_controllers_table_entry_* nvme_controllers_table_ = (struct nvme_controllers_table_entry_*) nvme_controllers_args.table; ++ ++ for(i = 0; i < nvme_controllers_table_entries; i++){ ++ nvme_controllers_table[i].id = (grub_uint16_t) nvme_controllers_table_[i].id; ++ grub_strcpy(nvme_controllers_table[i].wwpn, nvme_controllers_table_[i].wwpn); ++ grub_strcpy(nvme_controllers_table[i].nqn, nvme_controllers_table_[i].nqn); ++ } ++ ++ grub_ieee1275_close(ihandle); ++ ++ int nvme_controller_index; ++ int bufptr_pos2; ++ grub_dprintf("ofdisk","NVMeoF: found %d nvme controllers\n",(int) nvme_controllers_args.nentries); ++ ++ /* For each nvme controller */ ++ for(nvme_controller_index = 0; nvme_controller_index < (int) nvme_controllers_args.nentries; nvme_controller_index++){ ++ /* Open the nvme controller ++ * /pci@bus/fibre-channel@dev,func/nvme-of/controller@transport-addr,ctlr-id:nqn=tgt-subsystem-nqn ++ */ ++ ++ bufptr_pos2 = grub_snprintf (bufptr, 512, "/nvme-of/controller@%s,ffff:nqn=%s", ++ nvme_controllers_table[nvme_controller_index].wwpn, nvme_controllers_table[nvme_controller_index].nqn); ++ ++ grub_dprintf("ofdisk","NVMeoF: nvmeof controller=%s\n",buf); ++ ++ if(grub_ieee1275_open (buf, &ihandle)){ ++ grub_dprintf("ofdisk","failed to open the path=%s\n",buf); ++ continue; ++ } ++ ++ INIT_IEEE1275_COMMON (&nvme_namespaces_args.common, "call-method", 2, 2); ++ nvme_namespaces_args.method = (grub_ieee1275_cell_t) "get-namespace-list"; ++ nvme_namespaces_args.ihandle = ihandle; ++ nvme_namespaces_args.catch_result = 0; ++ ++ if (IEEE1275_CALL_ENTRY_FN (&nvme_namespaces_args) == -1) ++ { ++ grub_dprintf("ofdisk", "failed to get the nvme-namespace-list while iterating FCP disk path\n"); ++ grub_ieee1275_close(ihandle); ++ continue; ++ } ++ ++ grub_uint32_t *namespaces = (grub_uint32_t*) nvme_namespaces_args.table; ++ grub_dprintf("ofdisk","NVMeoF: found %d namespaces\n",(int)nvme_namespaces_args.nentries); ++ ++ grub_ieee1275_close(ihandle); ++ ++ grub_uint32_t namespace_index = 0; ++ for(namespace_index=0; namespace_index < nvme_namespaces_args.nentries; namespace_index++){ ++ grub_snprintf (bufptr+bufptr_pos2, 512, "/namespace@%"PRIxGRUB_UINT32_T,namespaces[namespace_index]); ++ grub_dprintf("ofdisk","NVMeoF: namespace=%s\n",buf); ++ dev_iterate_real(buf,buf); ++ } ++ ++ dev_iterate_real(buf,buf); ++ } ++ } ++ grub_free(buf); ++ return; ++} ++ ++static void ++dev_iterate (const struct grub_ieee1275_devalias *alias) ++{ ++ if (grub_strcmp (alias->type, "fcp") == 0) ++ { ++ // Iterate disks ++ dev_iterate_fcp_disks(alias); ++ ++ // Iterate NVMeoF ++ dev_iterate_fcp_nvmeof(alias); ++ + } + else if (grub_strcmp (alias->type, "vscsi") == 0) + { +-- +2.35.3 + diff --git a/0001-kern-efi-mm-Enlarge-the-default-heap-size.patch b/0001-kern-efi-mm-Enlarge-the-default-heap-size.patch new file mode 100644 index 0000000..149c5c1 --- /dev/null +++ b/0001-kern-efi-mm-Enlarge-the-default-heap-size.patch @@ -0,0 +1,32 @@ +From 3e08d9afd273b5dade84fec5f7f17113c47b6b75 Mon Sep 17 00:00:00 2001 +From: Gary Lin +Date: Fri, 2 Sep 2022 11:26:39 +0800 +Subject: [PATCH 1/2] kern/efi/mm: Enlarge the default heap size + +The default heap size (0x100000, 1MB) is not enough for the +openSUSE/SUSE theme, and the additional dynamical allocation of memory +regions significantly slows down the loading of the grub2 menu theme. +This commit increases the default heap size to 0x2000000, 32MB, and this +should be enough to cover the theme files. + +Signed-off-by: Gary Lin +--- + grub-core/kern/efi/mm.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c +index 48380d3..70d3e3d 100644 +--- a/grub-core/kern/efi/mm.c ++++ b/grub-core/kern/efi/mm.c +@@ -39,7 +39,7 @@ + #define MEMORY_MAP_SIZE 0x3000 + + /* The default heap size for GRUB itself in bytes. */ +-#define DEFAULT_HEAP_SIZE 0x100000 ++#define DEFAULT_HEAP_SIZE 0x2000000 + + static void *finish_mmap_buf = 0; + static grub_efi_uintn_t finish_mmap_size = 0; +-- +2.35.3 + diff --git a/0001-linux-fix-efi_relocate_kernel-failure.patch b/0001-linux-fix-efi_relocate_kernel-failure.patch new file mode 100644 index 0000000..33541ff --- /dev/null +++ b/0001-linux-fix-efi_relocate_kernel-failure.patch @@ -0,0 +1,182 @@ +From 80487d82ee1c179c01fad1a23f26fcca79c0ace5 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Mon, 26 Sep 2022 12:04:41 +0800 +Subject: [PATCH] linux: fix efi_relocate_kernel failure + +With the dynamic allocated heap in new memory manager, it could use up all +usable memory with no reservation on subsequent kernel loading leading to +following error: + + EFI stub: ERROR: Failed to allocate usable memory for kernel + EFI stub: ERROR: efi_relocate_kernel() failed! + EFI stub: ERROR: efi_main failed! + +The patch tries to returning the memory pages allocated by grub to the firmware +before handing over to linux kernel. This could eliminate the worry that we +have no limited amount of memory exclusively set for grub to guarentee the +memory requirement for booting subsequent component can be met. + +Signed-off-by: Michael Chang +--- + grub-core/Makefile.am | 7 +++++++ + grub-core/Makefile.core.def | 2 +- + grub-core/loader/efi/linux.c | 16 ++++++++++++++++ + grub-core/loader/i386/efi/linux.c | 13 ++++++++++--- + 4 files changed, 34 insertions(+), 4 deletions(-) + +diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am +index dc07ba6f8..3b1f101fd 100644 +--- a/grub-core/Makefile.am ++++ b/grub-core/Makefile.am +@@ -124,6 +124,7 @@ if COND_i386_efi + KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/kernel.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/efi.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/disk.h ++KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/linux.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/tsc.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/acpi.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/pci.h +@@ -185,6 +186,7 @@ if COND_x86_64_efi + KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/kernel.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/efi.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/disk.h ++KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/linux.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/tsc.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/pci.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/acpi.h +@@ -194,6 +196,7 @@ endif + if COND_ia64_efi + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/efi.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/disk.h ++KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/linux.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/acpi.h + endif + +@@ -281,6 +284,7 @@ endif + if COND_arm_efi + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/efi.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/disk.h ++KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/linux.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/arm/system.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/acpi.h + endif +@@ -288,18 +292,21 @@ endif + if COND_arm64_efi + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/efi.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/disk.h ++KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/linux.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/acpi.h + endif + + if COND_riscv32_efi + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/efi.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/disk.h ++KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/linux.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/acpi.h + endif + + if COND_riscv64_efi + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/efi.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/disk.h ++KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/linux.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/acpi.h + endif + +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index 211d2166b..a8c5684dd 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -392,6 +392,7 @@ kernel = { + extra_dist = kern/i386/realmode.S; + extra_dist = boot/i386/pc/lzma_decode.S; + extra_dist = kern/mips/cache_flush.S; ++ efi = loader/efi/linux.c; + }; + + program = { +@@ -1855,7 +1856,6 @@ module = { + riscv64 = loader/riscv/linux.c; + emu = loader/emu/linux.c; + common = loader/linux.c; +- efi = loader/efi/linux.c; + }; + + module = { +diff --git a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c +index 9265cf420..6ee0ca966 100644 +--- a/grub-core/loader/efi/linux.c ++++ b/grub-core/loader/efi/linux.c +@@ -23,6 +23,8 @@ + #include + #include + #include ++#include ++#include + + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wcast-align" +@@ -38,6 +40,8 @@ grub_efi_linux_boot (void *kernel_addr, grub_off_t handover_offset, + int offset = 0; + + #ifdef __x86_64__ ++ grub_efi_simple_text_output_interface_t *o; ++ o = grub_efi_system_table->con_out; + offset = 512; + #endif + +@@ -55,9 +59,21 @@ grub_efi_linux_boot (void *kernel_addr, grub_off_t handover_offset, + grub_dprintf ("linux", "kernel_addr: %p handover_offset: %p params: %p\n", + kernel_addr, (void *)(grub_efi_uintn_t)handover_offset, kernel_params); + hf = (handover_func)((char *)kernel_addr + handover_offset + offset); ++#ifdef __x86_64__ ++ grub_machine_fini (GRUB_LOADER_FLAG_NORETURN); ++#endif + hf (grub_efi_image_handle, grub_efi_system_table, kernel_params); + ++#ifdef __x86_64__ ++ efi_call_2 (o->output_string, o, L"cannot boot linux kernel via efi handover\r\n" ++ L"rebooting in 5 seconds... *\r\n"); ++ efi_call_1 (grub_efi_system_table->boot_services->stall, 5000000); ++ efi_call_4 (grub_efi_system_table->runtime_services->reset_system, ++ GRUB_EFI_RESET_COLD, GRUB_EFI_SUCCESS, 0, NULL); ++ for (;;) ; ++#else + return GRUB_ERR_BUG; ++#endif + } + + #pragma GCC diagnostic pop +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index 6b06a8f2f..b9b0d4a5f 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -90,6 +90,8 @@ kernel_alloc(grub_efi_uintn_t size, const char * const errmsg) + { + grub_uint64_t max = max_addresses[i].addr; + grub_efi_uintn_t pages; ++ grub_efi_status_t status; ++ grub_efi_boot_services_t *b; + + /* + * When we're *not* loading the kernel, or >4GB allocations aren't +@@ -104,9 +106,14 @@ kernel_alloc(grub_efi_uintn_t size, const char * const errmsg) + pages, (void *)(grub_addr_t)max); + + prev_max = max; +- addr = grub_efi_allocate_pages_real (max, pages, +- max_addresses[i].alloc_type, +- GRUB_EFI_LOADER_DATA); ++ b = grub_efi_system_table->boot_services; ++ status = efi_call_4 (b->allocate_pages, max_addresses[i].alloc_type, GRUB_EFI_LOADER_DATA, pages, &max); ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); ++ max = 0; ++ } ++ addr = (void *) ((grub_addr_t) max); + if (addr) + grub_dprintf ("linux", "Allocated at %p\n", addr); + } +-- +2.37.3 + 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-mm-Allow-dynamically-requesting-additional-memory-re.patch b/0001-mm-Allow-dynamically-requesting-additional-memory-re.patch new file mode 100644 index 0000000..364e106 --- /dev/null +++ b/0001-mm-Allow-dynamically-requesting-additional-memory-re.patch @@ -0,0 +1,133 @@ +From 23bca58a68264657f176885c3564d07c9938b7f6 Mon Sep 17 00:00:00 2001 +From: Patrick Steinhardt +Date: Thu, 21 Apr 2022 15:24:18 +1000 +Subject: [PATCH 1/5] mm: Allow dynamically requesting additional memory + regions + +Currently, all platforms will set up their heap on initialization of the +platform code. While this works mostly fine, it poses some limitations +on memory management on us. Most notably, allocating big chunks of +memory in the gigabyte range would require us to pre-request this many +bytes from the firmware and add it to the heap from the beginning on +some platforms like EFI. As this isn't needed for most configurations, +it is inefficient and may even negatively impact some usecases when, +e.g., chainloading. Nonetheless, allocating big chunks of memory is +required sometimes, where one example is the upcoming support for the +Argon2 key derival function in LUKS2. + +In order to avoid pre-allocating big chunks of memory, this commit +implements a runtime mechanism to add more pages to the system. When +a given allocation cannot be currently satisfied, we'll call a given +callback set up by the platform's own memory management subsystem, +asking it to add a memory area with at least "n" bytes. If this +succeeds, we retry searching for a valid memory region, which should +now succeed. + +If this fails, we try asking for "n" bytes, possibly spread across +multiple regions, in hopes that region merging means that we end up +with enough memory for things to work out. + +Signed-off-by: Patrick Steinhardt +Signed-off-by: Daniel Axtens +Tested-by: Stefan Berger +Reviewed-by: Daniel Kiper +Tested-by: Patrick Steinhardt +--- + grub-core/kern/mm.c | 30 ++++++++++++++++++++++++++++++ + include/grub/mm.h | 18 ++++++++++++++++++ + 2 files changed, 48 insertions(+) + +diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c +index 5c0a624..0bd9f75 100644 +--- a/grub-core/kern/mm.c ++++ b/grub-core/kern/mm.c +@@ -28,6 +28,9 @@ + - multiple regions may be used as free space. They may not be + contiguous. + ++ - if existing regions are insufficient to satisfy an allocation, a new ++ region can be requested from firmware. ++ + Regions are managed by a singly linked list, and the meta information is + stored in the beginning of each region. Space after the meta information + is used to allocate memory. +@@ -77,6 +80,7 @@ + + + grub_mm_region_t grub_mm_base; ++grub_mm_add_region_func_t grub_mm_add_region_fn; + + /* Get a header from the pointer PTR, and set *P and *R to a pointer + to the header and a pointer to its region, respectively. PTR must +@@ -364,6 +368,32 @@ grub_memalign (grub_size_t align, grub_size_t size) + goto again; + #endif + ++ case 1: ++ /* Request additional pages, contiguous */ ++ count++; ++ ++ if (grub_mm_add_region_fn != NULL && ++ grub_mm_add_region_fn (size, GRUB_MM_ADD_REGION_CONSECUTIVE) == GRUB_ERR_NONE) ++ goto again; ++ ++ /* fallthrough */ ++ ++ case 2: ++ /* Request additional pages, anything at all */ ++ count++; ++ ++ if (grub_mm_add_region_fn != NULL) ++ { ++ /* ++ * Try again even if this fails, in case it was able to partially ++ * satisfy the request ++ */ ++ grub_mm_add_region_fn (size, GRUB_MM_ADD_REGION_NONE); ++ goto again; ++ } ++ ++ /* fallthrough */ ++ + default: + break; + } +diff --git a/include/grub/mm.h b/include/grub/mm.h +index 1754635..67faebf 100644 +--- a/include/grub/mm.h ++++ b/include/grub/mm.h +@@ -20,6 +20,7 @@ + #ifndef GRUB_MM_H + #define GRUB_MM_H 1 + ++#include + #include + #include + #include +@@ -28,6 +29,23 @@ + # define NULL ((void *) 0) + #endif + ++#define GRUB_MM_ADD_REGION_NONE 0 ++#define GRUB_MM_ADD_REGION_CONSECUTIVE (1 << 0) ++ ++/* ++ * Function used to request memory regions of `grub_size_t` bytes. The second ++ * parameter is a bitfield of `GRUB_MM_ADD_REGION` flags. ++ */ ++typedef grub_err_t (*grub_mm_add_region_func_t) (grub_size_t, unsigned int); ++ ++/* ++ * Set this function pointer to enable adding memory-regions at runtime in case ++ * a memory allocation cannot be satisfied with existing regions. ++ */ ++#ifndef GRUB_MACHINE_EMU ++extern grub_mm_add_region_func_t EXPORT_VAR(grub_mm_add_region_fn); ++#endif ++ + void grub_mm_init_region (void *addr, grub_size_t size); + void *EXPORT_FUNC(grub_malloc) (grub_size_t size); + void *EXPORT_FUNC(grub_zalloc) (grub_size_t size); +-- +2.35.3 + diff --git a/0001-tpm-Disable-tpm-verifier-if-tpm-is-not-present.patch b/0001-tpm-Disable-tpm-verifier-if-tpm-is-not-present.patch new file mode 100644 index 0000000..1deb5b2 --- /dev/null +++ b/0001-tpm-Disable-tpm-verifier-if-tpm-is-not-present.patch @@ -0,0 +1,88 @@ +From 12378be5243c1c02ce28de2e5703e87197c69157 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Mon, 29 Aug 2022 11:28:28 +0800 +Subject: [PATCH] tpm: Disable tpm verifier if tpm is not present + +This helps to prevent out of memory error when reading large files via disablig +tpm device as verifier has to read all content into memory in one chunk to +measure the hash and extend to tpm. + +Signed-off-by: Michael Chang +--- + grub-core/commands/efi/tpm.c | 37 +++++++++++++++++++++++++++++++++++++ + grub-core/commands/tpm.c | 4 ++++ + include/grub/tpm.h | 1 + + 3 files changed, 42 insertions(+) + +--- a/grub-core/commands/efi/tpm.c ++++ b/grub-core/commands/efi/tpm.c +@@ -349,3 +349,40 @@ + + return result; + } ++ ++int ++grub_tpm_present () ++{ ++ grub_efi_handle_t tpm_handle; ++ grub_efi_uint8_t protocol_version; ++ ++ if (!grub_tpm_handle_find (&tpm_handle, &protocol_version)) ++ return 0; ++ ++ if (protocol_version == 1) ++ { ++ grub_efi_tpm_protocol_t *tpm; ++ ++ tpm = grub_efi_open_protocol (tpm_handle, &tpm_guid, ++ GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); ++ if (!tpm) ++ { ++ grub_dprintf ("tpm", "Cannot open TPM protocol\n"); ++ return 0; ++ } ++ return grub_tpm1_present (tpm); ++ } ++ else ++ { ++ grub_efi_tpm2_protocol_t *tpm; ++ ++ tpm = grub_efi_open_protocol (tpm_handle, &tpm2_guid, ++ GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); ++ if (!tpm) ++ { ++ grub_dprintf ("tpm", "Cannot open TPM protocol\n"); ++ return 0; ++ } ++ return grub_tpm2_present (tpm); ++ } ++} +--- a/grub-core/commands/tpm.c ++++ b/grub-core/commands/tpm.c +@@ -291,6 +291,8 @@ + + GRUB_MOD_INIT (tpm) + { ++ if (!grub_tpm_present()) ++ return; + grub_verifier_register (&grub_tpm_verifier); + + cmd = grub_register_extcmd ("tpm_record_pcrs", grub_tpm_record_pcrs, 0, +@@ -301,6 +303,8 @@ + + GRUB_MOD_FINI (tpm) + { ++ if (!grub_tpm_present()) ++ return; + grub_verifier_unregister (&grub_tpm_verifier); + grub_unregister_extcmd (cmd); + } +--- a/include/grub/tpm.h ++++ b/include/grub/tpm.h +@@ -44,5 +44,6 @@ + grub_uint8_t pcr, const char *description); + struct grub_tpm_digest *grub_tpm_read_pcr (grub_uint8_t index, const char *algo); + void grub_tpm_digest_free (struct grub_tpm_digest *d); ++int grub_tpm_present (void); + + #endif diff --git a/0002-commands-efi-tpm-Use-grub_strcpy-instead-of-grub_mem.patch b/0002-commands-efi-tpm-Use-grub_strcpy-instead-of-grub_mem.patch new file mode 100644 index 0000000..77b5555 --- /dev/null +++ b/0002-commands-efi-tpm-Use-grub_strcpy-instead-of-grub_mem.patch @@ -0,0 +1,40 @@ +From 1f41f020f73131574cd7aee4e0e09d4c56277d1e Mon Sep 17 00:00:00 2001 +From: Lu Ken +Date: Wed, 13 Jul 2022 10:06:11 +0800 +Subject: [PATCH 2/3] commands/efi/tpm: Use grub_strcpy() instead of + grub_memcpy() + +The event description is a string, so using grub_strcpy() is cleaner than +using grub_memcpy(). + +Signed-off-by: Lu Ken +Reviewed-by: Daniel Kiper +--- + grub-core/commands/efi/tpm.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/grub-core/commands/efi/tpm.c b/grub-core/commands/efi/tpm.c +index 19737b462..e032617d8 100644 +--- a/grub-core/commands/efi/tpm.c ++++ b/grub-core/commands/efi/tpm.c +@@ -177,7 +177,7 @@ grub_tpm1_log_event (grub_efi_handle_t tpm_handle, unsigned char *buf, + event->PCRIndex = pcr; + event->EventType = EV_IPL; + event->EventSize = grub_strlen (description) + 1; +- grub_memcpy (event->Event, description, event->EventSize); ++ grub_strcpy ((char *) event->Event, description); + + algorithm = TCG_ALG_SHA; + status = efi_call_7 (tpm->log_extend_event, tpm, (grub_addr_t) buf, (grub_uint64_t) size, +@@ -299,7 +299,7 @@ grub_tpm2_log_event (grub_efi_handle_t tpm_handle, unsigned char *buf, + event->Header.EventType = EV_IPL; + event->Size = + sizeof (*event) - sizeof (event->Event) + grub_strlen (description) + 1; +- grub_memcpy (event->Event, description, grub_strlen (description) + 1); ++ grub_strcpy ((char *) event->Event, description); + + status = efi_call_5 (tpm->hash_log_extend_event, tpm, 0, (grub_addr_t) buf, + (grub_uint64_t) size, event); +-- +2.35.3 + 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/0002-devmapper-getroot-Set-up-cheated-LUKS2-cryptodisk-mo.patch b/0002-devmapper-getroot-Set-up-cheated-LUKS2-cryptodisk-mo.patch new file mode 100644 index 0000000..a03e641 --- /dev/null +++ b/0002-devmapper-getroot-Set-up-cheated-LUKS2-cryptodisk-mo.patch @@ -0,0 +1,127 @@ +From a25627c13b7e1e6998a14b5dd23b04b28465d737 Mon Sep 17 00:00:00 2001 +From: Josselin Poiret via Grub-devel +Date: Tue, 14 Jun 2022 15:47:30 +0200 +Subject: [PATCH 02/10] devmapper/getroot: Set up cheated LUKS2 cryptodisk + mount from DM parameters + +This lets a LUKS2 cryptodisk have its cipher and hash filled out, +otherwise they wouldn't be initialized if cheat mounted. +--- + grub-core/osdep/devmapper/getroot.c | 91 +++++++++++++++++++++++++++++++++++- + 1 file changed, 90 insertions(+), 1 deletion(-) + +--- a/grub-core/osdep/devmapper/getroot.c ++++ b/grub-core/osdep/devmapper/getroot.c +@@ -51,6 +51,8 @@ + #include + #include + ++#include ++ + static int + grub_util_open_dm (const char *os_dev, struct dm_tree **tree, + struct dm_tree_node **node) +@@ -186,7 +188,6 @@ + && lastsubdev) + { + char *grdev = grub_util_get_grub_dev (lastsubdev); +- dm_tree_free (tree); + if (grdev) + { + grub_err_t err; +@@ -194,7 +195,95 @@ + if (err) + grub_util_error (_("can't mount encrypted volume `%s': %s"), + lastsubdev, grub_errmsg); ++ if (strncmp (uuid, "CRYPT-LUKS2-", sizeof ("CRYPT-LUKS2-") - 1) == 0) ++ { ++ /* set LUKS2 cipher from dm parameters, since it is not ++ * possible to determine the correct one without ++ * unlocking, as there might be multiple segments. ++ */ ++ grub_disk_t source; ++ grub_cryptodisk_t cryptodisk; ++ grub_uint64_t start, length; ++ char *target_type; ++ char *params; ++ const char *name; ++ char *cipher, *cipher_mode; ++ struct dm_task *dmt; ++ char *seek_head, *c; ++ unsigned int remaining; ++ ++ source = grub_disk_open (grdev); ++ cryptodisk = grub_cryptodisk_get_by_source_disk (source); ++ grub_disk_close (source); ++ ++ name = dm_tree_node_get_name (node); ++ ++ grub_util_info ("populating parameters of cryptomount `%s' from DM device `%s'", ++ uuid, name); ++ ++ dmt = dm_task_create (DM_DEVICE_TABLE); ++ if (dmt == 0) ++ grub_util_error (_("can't create dm task DM_DEVICE_TABLE")); ++ if (dm_task_set_name (dmt, name) == 0) ++ grub_util_error (_("can't set dm task name to `%s'"), name); ++ if (dm_task_run (dmt) == 0) ++ grub_util_error (_("can't run dm task for `%s'"), name); ++ /* dm_get_next_target doesn't have any error modes, everything has ++ * been handled by dm_task_run. ++ */ ++ dm_get_next_target (dmt, NULL, &start, &length, ++ &target_type, ¶ms); ++ if (strncmp (target_type, "crypt", sizeof ("crypt")) != 0) ++ grub_util_error (_("dm target of type `%s' is not `crypt'"), ++ target_type); ++ ++ /* dm target parameters for dm-crypt is ++ * [<#opt_params> ...] ++ */ ++ c = params; ++ remaining = grub_strlen (c); ++ ++ /* first, get the cipher name from the cipher */ ++ if (!(seek_head = grub_memchr (c, '-', remaining))) ++ grub_util_error (_("can't get cipher from dm-crypt parameters `%s'"), ++ params); ++ cipher = grub_strndup (c, seek_head - c); ++ remaining -= seek_head - c + 1; ++ c = seek_head + 1; ++ ++ /* now, the cipher mode */ ++ if (!(seek_head = grub_memchr (c, ' ', remaining))) ++ grub_util_error (_("can't get cipher mode from dm-crypt parameters `%s'"), ++ params); ++ cipher_mode = grub_strndup (c, seek_head - c); ++ remaining -= seek_head - c + 1; ++ c = seek_head + 1; ++ ++ err = grub_cryptodisk_setcipher (cryptodisk, cipher, cipher_mode); ++ if (err) ++ { ++ grub_util_error (_("can't set cipher of cryptodisk `%s' to `%s' with mode `%s'"), ++ uuid, cipher, cipher_mode); ++ } ++ ++ grub_free (cipher); ++ grub_free (cipher_mode); ++ ++ /* This is the only hash usable by PBKDF2, and we don't ++ * have Argon2 support yet, so set it by default, ++ * otherwise grub-probe would miss the required ++ * abstraction ++ */ ++ cryptodisk->hash = grub_crypto_lookup_md_by_name ("sha256"); ++ if (cryptodisk->hash == 0) ++ { ++ grub_util_error (_("can't lookup hash sha256 by name")); ++ } ++ ++ dm_task_destroy (dmt); ++ } + } ++ dm_tree_free (tree); + grub_free (grdev); + } + else diff --git a/0002-ieee1275-implement-vec5-for-cas-negotiation.patch b/0002-ieee1275-implement-vec5-for-cas-negotiation.patch new file mode 100644 index 0000000..27e05ab --- /dev/null +++ b/0002-ieee1275-implement-vec5-for-cas-negotiation.patch @@ -0,0 +1,73 @@ +From 6c7c4007ad621029295797b439158d36d0f62487 Mon Sep 17 00:00:00 2001 +From: Diego Domingos +Date: Thu, 25 Aug 2022 11:37:56 -0400 +Subject: [PATCH 2/2] ieee1275: implement vec5 for cas negotiation + +As a legacy support, if the vector 5 is not implemented, Power +Hypervisor will consider the max CPUs as 64 instead 256 currently +supported during client-architecture-support negotiation. + +This patch implements the vector 5 and set the MAX CPUs to 256 while +setting the others values to 0 (default). + +Signed-off-by: Diego Domingos +Signed-off-by: Robbie Harwood +--- + grub-core/kern/ieee1275/init.c | 20 +++++++++++++++++++- + 1 file changed, 19 insertions(+), 1 deletion(-) + +diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c +index 7d7178d3e..3aa40313f 100644 +--- a/grub-core/kern/ieee1275/init.c ++++ b/grub-core/kern/ieee1275/init.c +@@ -311,6 +311,18 @@ struct option_vector2 { + grub_uint8_t max_pft_size; + } __attribute__((packed)); + ++struct option_vector5 { ++ grub_uint8_t byte1; ++ grub_uint8_t byte2; ++ grub_uint8_t byte3; ++ grub_uint8_t cmo; ++ grub_uint8_t associativity; ++ grub_uint8_t bin_opts; ++ grub_uint8_t micro_checkpoint; ++ grub_uint8_t reserved0; ++ grub_uint32_t max_cpus; ++} __attribute__((packed)); ++ + struct pvr_entry { + grub_uint32_t mask; + grub_uint32_t entry; +@@ -329,6 +341,8 @@ struct cas_vector { + grub_uint16_t vec3; + grub_uint8_t vec4_size; + grub_uint16_t vec4; ++ grub_uint8_t vec5_size; ++ struct option_vector5 vec5; + } __attribute__((packed)); + + /* Call ibm,client-architecture-support to try to get more RMA. +@@ -349,7 +363,7 @@ grub_ieee1275_ibm_cas (void) + } args; + struct cas_vector vector = { + .pvr_list = { { 0x00000000, 0xffffffff } }, /* any processor */ +- .num_vecs = 4 - 1, ++ .num_vecs = 5 - 1, + .vec1_size = 0, + .vec1 = 0x80, /* ignore */ + .vec2_size = 1 + sizeof(struct option_vector2) - 2, +@@ -360,6 +374,10 @@ grub_ieee1275_ibm_cas (void) + .vec3 = 0x00e0, // ask for FP + VMX + DFP but don't halt if unsatisfied + .vec4_size = 2 - 1, + .vec4 = 0x0001, // set required minimum capacity % to the lowest value ++ .vec5_size = 1 + sizeof(struct option_vector5) - 2, ++ .vec5 = { ++ 0, 0, 0, 0, 0, 0, 0, 0, 256 ++ } + }; + + INIT_IEEE1275_COMMON (&args.common, "call-method", 3, 2); +-- +2.35.3 + diff --git a/0002-ieee1275-ofpath-enable-NVMeoF-logical-device-transla.patch b/0002-ieee1275-ofpath-enable-NVMeoF-logical-device-transla.patch new file mode 100644 index 0000000..19a1527 --- /dev/null +++ b/0002-ieee1275-ofpath-enable-NVMeoF-logical-device-transla.patch @@ -0,0 +1,373 @@ +From 9e61624db77e5073961126457f599bc70e877fd1 Mon Sep 17 00:00:00 2001 +From: Diego Domingos +Date: Tue, 15 Mar 2022 15:59:41 -0400 +Subject: [PATCH 2/4] ieee1275/ofpath: enable NVMeoF logical device translation + +This patch add code to enable the translation of logical devices to the of NVMeoFC paths. +--- + grub-core/osdep/linux/ofpath.c | 260 +++++++++++++++++++++++++++++++-- + include/grub/util/ofpath.h | 29 ++++ + 2 files changed, 280 insertions(+), 9 deletions(-) + +diff --git a/grub-core/osdep/linux/ofpath.c b/grub-core/osdep/linux/ofpath.c +index 89beceef4..212782d3f 100644 +--- a/grub-core/osdep/linux/ofpath.c ++++ b/grub-core/osdep/linux/ofpath.c +@@ -137,7 +137,7 @@ trim_newline (char *path) + *end-- = '\0'; + } + +-#define MAX_DISK_CAT 64 ++#define MAX_DISK_CAT 512 + + static char * + find_obppath (const char *sysfs_path_orig) +@@ -313,6 +313,69 @@ get_basename(char *p) + return ret; + } + ++ ++void ++add_filename_to_pile(char *filename, struct ofpath_files_list_root* root){ ++ struct ofpath_files_list_node* file; ++ ++ file = malloc(sizeof(struct ofpath_files_list_node)); ++ ++ file->filename = filename; ++ ++ if(root->first == NULL){ ++ root->items = 1; ++ root->first = file; ++ file->next = NULL; ++ } else { ++ root->items++; ++ file->next = root->first; ++ root->first = file; ++ } ++} ++ ++ ++void ++find_file(char* filename, char* directory, struct ofpath_files_list_root* root, int max_depth, int depth){ ++ struct dirent *ep; ++ struct stat statbuf; ++ DIR *dp; ++ ++ if(depth > max_depth){ ++ return; ++ } ++ ++ if((dp = opendir(directory)) == NULL){ ++ ++ return; ++ } ++ ++ while((ep = readdir(dp)) != NULL){ ++ ++ char* full_path = malloc(1024*sizeof(char)); ++ snprintf(full_path,1024,"%s/%s",directory,ep->d_name); ++ ++ lstat(full_path,&statbuf); ++ ++ if(S_ISLNK(statbuf.st_mode)){ ++ ++ continue; ++ } ++ ++ if(!strcmp(ep->d_name,".") || !strcmp(ep->d_name,"..")){ ++ continue; ++ } ++ ++ if(!strcmp(ep->d_name,filename)){ ++ add_filename_to_pile(full_path, root); ++ } ++ ++ find_file(filename, full_path, root, max_depth, depth+1); ++ ++ } ++ closedir(dp); ++} ++ ++ + static char * + of_path_of_vdisk(const char *sys_devname __attribute__((unused)), + const char *device, +@@ -351,7 +414,142 @@ of_path_of_ide(const char *sys_devname __attribute__((unused)), const char *devi + return ret; + } + +-#ifdef __sparc__ ++char* ++of_find_fc_host(char* host_wwpn){ ++ ++ FILE* fp; ++ char *buf; ++ char portname_filename[sizeof("port_name")] = "port_name"; ++ char devices_path[sizeof("/sys/devices")] = "/sys/devices"; ++ ++ struct ofpath_files_list_root* portnames_file_list; ++ ++ portnames_file_list=malloc(sizeof(portnames_file_list)); ++ portnames_file_list->items=0; ++ portnames_file_list->first=NULL; ++ ++ find_file(portname_filename, devices_path, portnames_file_list, 10, 0); ++ ++ struct ofpath_files_list_node* node = portnames_file_list->first; ++ while(node != NULL){ ++ fp = fopen(node->filename,"r"); ++ buf = malloc(sizeof(char)*512); ++ fscanf(fp, "%s", buf); ++ fclose(fp); ++ if((strcmp(buf,host_wwpn) == 0) && grub_strstr(node->filename, "fc_host")){ ++ return node->filename; ++ } ++ node = node->next; ++ } ++ ++ return NULL; ++} ++ ++void ++of_path_get_nvmeof_adapter_info(char* sysfs_path, ++ struct ofpath_nvmeof_info* nvmeof_info){ ++ ++ FILE *fp; ++ char *buf, *buf2, *buf3; ++ ++ nvmeof_info->host_wwpn = malloc(sizeof(char)*256); ++ nvmeof_info->target_wwpn = malloc(sizeof(char)*256); ++ nvmeof_info->nqn = malloc(sizeof(char)*256); ++ ++ buf = malloc(sizeof(char)*512); ++ snprintf(buf,512,"%s/subsysnqn",sysfs_path); ++ fp = fopen(buf,"r"); ++ fscanf(fp, "%s", nvmeof_info->nqn); ++ fclose(fp); ++ ++ snprintf(buf,512,"%s/cntlid",sysfs_path); ++ fp = fopen(buf,"r"); ++ fscanf(fp, "%u", &(nvmeof_info->cntlid)); ++ fclose(fp); ++ ++ //snprintf(buf,512,"%s/nsid",sysfs_path); ++ //fp = fopen(buf,"r"); ++ //fscanf(fp, "%u", &(nvmeof_info->nsid)); ++ //fclose(fp); ++ ++ snprintf(buf,512,"%s/address",sysfs_path); ++ fp = fopen(buf,"r"); ++ buf2 = malloc(sizeof(char)*512); ++ fscanf(fp, "%s", buf2); ++ fclose(fp); ++ ++ nvmeof_info->host_wwpn = strrchr(buf2,'-')+1; ++ ++ buf3=strchr(buf2,'-')+1; ++ buf3=strchr(buf3,'-')+1; ++ nvmeof_info->target_wwpn = buf3; ++ buf3 = strchr(nvmeof_info->target_wwpn,','); ++ *buf3 = '\0'; ++ ++ ++ free(buf); ++ ++ return; ++} ++ ++#define MAX_NVME_NSID_DIGITS 6 ++ ++static char * ++of_path_get_nvme_controller_name_node(const char* devname) ++{ ++ char *controller_node, *end; ++ ++ controller_node = strdup(devname); ++ ++ end = grub_strchr(controller_node+1, 'n'); ++ ++ if(end != NULL){ ++ *end = '\0'; ++ } ++ ++ return controller_node; ++} ++ ++unsigned int ++of_path_get_nvme_nsid(const char* devname) ++{ ++ unsigned int nsid; ++ char *sysfs_path, *buf; ++ FILE *fp; ++ ++ buf=malloc(sizeof(char)*512); ++ ++ sysfs_path = block_device_get_sysfs_path_and_link (devname); ++ ++ snprintf(buf,512,"%s/%s/nsid",sysfs_path,devname); ++ fp = fopen(buf,"r"); ++ fscanf(fp, "%u", &(nsid)); ++ fclose(fp); ++ ++ free(sysfs_path); ++ free(buf); ++ ++ return nsid; ++ ++} ++ ++static char * ++nvme_get_syspath(const char *nvmedev) ++{ ++ char *sysfs_path, *controller_node; ++ sysfs_path = block_device_get_sysfs_path_and_link (nvmedev); ++ ++ if(strstr(sysfs_path,"nvme-subsystem")){ ++ controller_node = of_path_get_nvme_controller_name_node(nvmedev); ++ strcat(sysfs_path,"/"); ++ strcat(sysfs_path,controller_node); ++ sysfs_path = xrealpath(sysfs_path); ++ } ++ ++ return sysfs_path; ++} ++ ++ + static char * + of_path_of_nvme(const char *sys_devname __attribute__((unused)), + const char *device, +@@ -360,6 +558,7 @@ of_path_of_nvme(const char *sys_devname __attribute__((unused)), + { + char *sysfs_path, *of_path, disk[MAX_DISK_CAT]; + const char *digit_string, *part_end; ++ int chars_written; + + digit_string = trailing_digits (device); + part_end = devicenode + strlen (devicenode) - 1; +@@ -379,15 +578,61 @@ of_path_of_nvme(const char *sys_devname __attribute__((unused)), + /* Remove the p. */ + *end = '\0'; + sscanf (digit_string, "%d", &part); +- snprintf (disk, sizeof (disk), "/disk@1:%c", 'a' + (part - 1)); +- sysfs_path = block_device_get_sysfs_path_and_link (nvmedev); ++ ++ sysfs_path = nvme_get_syspath(nvmedev); ++ ++ /* If is a NVMeoF */ ++ if(strstr(sysfs_path,"nvme-fabrics")){ ++ struct ofpath_nvmeof_info* nvmeof_info; ++ nvmeof_info = malloc(sizeof(nvmeof_info)); ++ ++ of_path_get_nvmeof_adapter_info(sysfs_path, nvmeof_info); ++ ++ sysfs_path = of_find_fc_host(nvmeof_info->host_wwpn); ++ ++ chars_written = snprintf(disk,sizeof(disk),"/nvme-of/controller@%s,%x:nqn=%s", ++ nvmeof_info->target_wwpn, ++ 0xffff, ++ nvmeof_info->nqn); ++ ++ unsigned int nsid = of_path_get_nvme_nsid(nvmedev); ++ ++ if(nsid){ ++ snprintf(disk+chars_written,sizeof(disk) - chars_written, ++ "/namespace@%x:%d",nsid, part); ++ } ++ ++ } else { ++ snprintf (disk, sizeof (disk), "/disk@1:%c", 'a' + (part - 1)); ++ } + free (nvmedev); + } + else + { + /* We do not have the parition. */ +- snprintf (disk, sizeof (disk), "/disk@1"); +- sysfs_path = block_device_get_sysfs_path_and_link (device); ++ sysfs_path = nvme_get_syspath (device); ++ if(strstr(sysfs_path,"nvme-fabrics")){ ++ struct ofpath_nvmeof_info* nvmeof_info; ++ nvmeof_info = malloc(sizeof(nvmeof_info)); ++ ++ of_path_get_nvmeof_adapter_info(sysfs_path, nvmeof_info); ++ ++ sysfs_path = of_find_fc_host(nvmeof_info->host_wwpn); ++ ++ chars_written = snprintf(disk,sizeof(disk),"/nvme-of/controller@%s,%x:nqn=%s", ++ nvmeof_info->target_wwpn, ++ 0xffff, ++ nvmeof_info->nqn); ++ ++ unsigned int nsid = of_path_get_nvme_nsid(device); ++ if(nsid){ ++ snprintf(disk+chars_written,sizeof(disk) - chars_written, ++ "/namespace@%x",nsid); ++ } ++ } else { ++ snprintf (disk, sizeof (disk), "/disk@1"); ++ } ++ + } + + of_path = find_obppath (sysfs_path); +@@ -398,7 +643,6 @@ of_path_of_nvme(const char *sys_devname __attribute__((unused)), + free (sysfs_path); + return of_path; + } +-#endif + + static void + of_fc_port_name(const char *path, const char *subpath, char *port_name) +@@ -840,11 +1084,9 @@ grub_util_devname_to_ofpath (const char *sys_devname) + /* All the models I've seen have a devalias "floppy". + New models have no floppy at all. */ + ofpath = xstrdup ("floppy"); +-#ifdef __sparc__ + else if (device[0] == 'n' && device[1] == 'v' && device[2] == 'm' + && device[3] == 'e') + ofpath = of_path_of_nvme (name_buf, device, devnode, devicenode); +-#endif + else + { + grub_util_warn (_("unknown device type %s"), device); +diff --git a/include/grub/util/ofpath.h b/include/grub/util/ofpath.h +index b43c523cb..a0ec30620 100644 +--- a/include/grub/util/ofpath.h ++++ b/include/grub/util/ofpath.h +@@ -3,4 +3,33 @@ + + char *grub_util_devname_to_ofpath (const char *devname); + ++struct ofpath_files_list_node { ++ char* filename; ++ struct ofpath_files_list_node* next; ++}; ++ ++struct ofpath_files_list_root { ++ int items; ++ struct ofpath_files_list_node* first; ++}; ++ ++struct ofpath_nvmeof_info { ++ char* host_wwpn; ++ char* target_wwpn; ++ char* nqn; ++ int cntlid; ++ int nsid; ++}; ++ ++void of_path_get_nvmeof_adapter_info(char* sysfs_path, ++ struct ofpath_nvmeof_info* nvmeof_info); ++ ++unsigned int of_path_get_nvme_nsid(const char* devname); ++ ++void add_filename_to_pile(char *filename, struct ofpath_files_list_root* root); ++ ++void find_file(char* filename, char* directory, struct ofpath_files_list_root* root, int max_depth, int depth); ++ ++char* of_find_fc_host(char* host_wwpn); ++ + #endif /* ! GRUB_OFPATH_MACHINE_UTIL_HEADER */ +-- +2.35.3 + diff --git a/0002-kern-efi-mm-Always-request-a-fixed-number-of-pages-o.patch b/0002-kern-efi-mm-Always-request-a-fixed-number-of-pages-o.patch new file mode 100644 index 0000000..b0f3ed4 --- /dev/null +++ b/0002-kern-efi-mm-Always-request-a-fixed-number-of-pages-o.patch @@ -0,0 +1,106 @@ +From 834cb2ca9ed2d9d7a6926e598accdfe280b615da Mon Sep 17 00:00:00 2001 +From: Patrick Steinhardt +Date: Thu, 21 Apr 2022 15:24:19 +1000 +Subject: [PATCH 2/5] kern/efi/mm: Always request a fixed number of pages on + init + +When initializing the EFI memory subsystem, we will by default request +a quarter of the available memory, bounded by a minimum/maximum value. +Given that we're about to extend the EFI memory system to dynamically +request additional pages from the firmware as required, this scaling of +requested memory based on available memory will not make a lot of sense +anymore. + +Remove this logic as a preparatory patch such that we'll instead defer +to the runtime memory allocator. Note that ideally, we'd want to change +this after dynamic requesting of pages has been implemented for the EFI +platform. But because we'll need to split up initialization of the +memory subsystem and the request of pages from the firmware, we'd have +to duplicate quite some logic at first only to remove it afterwards +again. This seems quite pointless, so we instead have patches slightly +out of order. + +Signed-off-by: Patrick Steinhardt +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +Tested-by: Patrick Steinhardt +--- + grub-core/kern/efi/mm.c | 35 +++-------------------------------- + 1 file changed, 3 insertions(+), 32 deletions(-) + +diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c +index 67a691d..2874522 100644 +--- a/grub-core/kern/efi/mm.c ++++ b/grub-core/kern/efi/mm.c +@@ -38,9 +38,8 @@ + a multiplier of 4KB. */ + #define MEMORY_MAP_SIZE 0x3000 + +-/* The minimum and maximum heap size for GRUB itself. */ +-#define MIN_HEAP_SIZE 0x100000 +-#define MAX_HEAP_SIZE (1600 * 0x100000) ++/* The default heap size for GRUB itself in bytes. */ ++#define DEFAULT_HEAP_SIZE 0x100000 + + static void *finish_mmap_buf = 0; + static grub_efi_uintn_t finish_mmap_size = 0; +@@ -514,23 +513,6 @@ filter_memory_map (grub_efi_memory_descriptor_t *memory_map, + return filtered_desc; + } + +-/* Return the total number of pages. */ +-static grub_efi_uint64_t +-get_total_pages (grub_efi_memory_descriptor_t *memory_map, +- grub_efi_uintn_t desc_size, +- grub_efi_memory_descriptor_t *memory_map_end) +-{ +- grub_efi_memory_descriptor_t *desc; +- grub_efi_uint64_t total = 0; +- +- for (desc = memory_map; +- desc < memory_map_end; +- desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size)) +- total += desc->num_pages; +- +- return total; +-} +- + /* Add memory regions. */ + static void + add_memory_regions (grub_efi_memory_descriptor_t *memory_map, +@@ -619,8 +601,6 @@ grub_efi_mm_init (void) + grub_efi_memory_descriptor_t *filtered_memory_map_end; + grub_efi_uintn_t map_size; + grub_efi_uintn_t desc_size; +- grub_efi_uint64_t total_pages; +- grub_efi_uint64_t required_pages; + int mm_status; + + /* Prepare a memory region to store two memory maps. */ +@@ -660,22 +640,13 @@ grub_efi_mm_init (void) + filtered_memory_map_end = filter_memory_map (memory_map, filtered_memory_map, + desc_size, memory_map_end); + +- /* By default, request a quarter of the available memory. */ +- total_pages = get_total_pages (filtered_memory_map, desc_size, +- filtered_memory_map_end); +- required_pages = (total_pages >> 2); +- if (required_pages < BYTES_TO_PAGES (MIN_HEAP_SIZE)) +- required_pages = BYTES_TO_PAGES (MIN_HEAP_SIZE); +- else if (required_pages > BYTES_TO_PAGES (MAX_HEAP_SIZE)) +- required_pages = BYTES_TO_PAGES (MAX_HEAP_SIZE); +- + /* Sort the filtered descriptors, so that GRUB can allocate pages + from smaller regions. */ + sort_memory_map (filtered_memory_map, desc_size, filtered_memory_map_end); + + /* Allocate memory regions for GRUB's memory management. */ + add_memory_regions (filtered_memory_map, desc_size, +- filtered_memory_map_end, required_pages); ++ filtered_memory_map_end, BYTES_TO_PAGES (DEFAULT_HEAP_SIZE)); + + #if 0 + /* For debug. */ +-- +2.35.3 + diff --git a/0002-mm-Defer-the-disk-cache-invalidation.patch b/0002-mm-Defer-the-disk-cache-invalidation.patch new file mode 100644 index 0000000..ddab6ba --- /dev/null +++ b/0002-mm-Defer-the-disk-cache-invalidation.patch @@ -0,0 +1,68 @@ +From 4284d40799aaf5aab11c690f232ce0a191dcfbdb Mon Sep 17 00:00:00 2001 +From: Gary Lin +Date: Fri, 16 Sep 2022 10:59:55 +0800 +Subject: [PATCH 2/2] mm: Defer the disk cache invalidation + +When the heap memory is used up, the memory management code invalidates +the disk caches first and then requests the additional memory regioins. +Although this could minimize the memory usage, it hurts the loading time +since the disk caches may always miss. + +This patch defers the disk cache invalidation to avoid the possible +delays. + +Signen-off-by: Gary Lin +--- + grub-core/kern/mm.c | 22 +++++++--------------- + 1 file changed, 7 insertions(+), 15 deletions(-) + +diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c +index 0bd9f75..5280e8c 100644 +--- a/grub-core/kern/mm.c ++++ b/grub-core/kern/mm.c +@@ -355,20 +355,6 @@ grub_memalign (grub_size_t align, grub_size_t size) + switch (count) + { + case 0: +- /* Invalidate disk caches. */ +- grub_disk_cache_invalidate_all (); +- count++; +- goto again; +- +-#if 0 +- case 1: +- /* Unload unneeded modules. */ +- grub_dl_unload_unneeded (); +- count++; +- goto again; +-#endif +- +- case 1: + /* Request additional pages, contiguous */ + count++; + +@@ -378,7 +364,7 @@ grub_memalign (grub_size_t align, grub_size_t size) + + /* fallthrough */ + +- case 2: ++ case 1: + /* Request additional pages, anything at all */ + count++; + +@@ -394,6 +380,12 @@ grub_memalign (grub_size_t align, grub_size_t size) + + /* fallthrough */ + ++ case 2: ++ /* Invalidate disk caches. */ ++ grub_disk_cache_invalidate_all (); ++ count++; ++ goto again; ++ + default: + break; + } +-- +2.35.3 + 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/0003-disk-cryptodisk-When-cheatmounting-use-the-sector-in.patch b/0003-disk-cryptodisk-When-cheatmounting-use-the-sector-in.patch new file mode 100644 index 0000000..a80501d --- /dev/null +++ b/0003-disk-cryptodisk-When-cheatmounting-use-the-sector-in.patch @@ -0,0 +1,71 @@ +From 5b694a13545224c2d21afc3e94831be1bcc85770 Mon Sep 17 00:00:00 2001 +From: Fabian Vogt +Date: Tue, 14 Jun 2022 15:55:21 +0200 +Subject: [PATCH 03/10] disk/cryptodisk: When cheatmounting, use the sector + info of the cheat device + +When using grub-probe with cryptodisk, the mapped block device from the host +is used directly instead of decrypting the source device in GRUB code. +In that case, the sector size and count of the host device needs to be used. +This is especially important when using luks2, which does not assign +total_sectors and log_sector_size when scanning, but only later when the +segments in the JSON area are evaluated. With an unset log_sector_size, +grub_open_device complains. + +This fixes grub-probe failing with +"error: sector sizes of 1 bytes aren't supported yet." + +Signed-off-by: Fabian Vogt +--- + grub-core/disk/cryptodisk.c | 20 ++++++++++++++++++-- + 1 file changed, 18 insertions(+), 2 deletions(-) + +diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c +index 6d22bf871c..ae8790f10f 100644 +--- a/grub-core/disk/cryptodisk.c ++++ b/grub-core/disk/cryptodisk.c +@@ -698,16 +698,31 @@ grub_cryptodisk_open (const char *name, grub_disk_t disk) + if (!dev) + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "No such device"); + +- disk->log_sector_size = dev->log_sector_size; +- + #ifdef GRUB_UTIL + if (dev->cheat) + { ++ grub_uint64_t cheat_dev_size; ++ unsigned int cheat_log_sector_size; ++ + if (!GRUB_UTIL_FD_IS_VALID (dev->cheat_fd)) + dev->cheat_fd = grub_util_fd_open (dev->cheat, GRUB_UTIL_FD_O_RDONLY); + if (!GRUB_UTIL_FD_IS_VALID (dev->cheat_fd)) + return grub_error (GRUB_ERR_IO, N_("cannot open `%s': %s"), + dev->cheat, grub_util_fd_strerror ()); ++ ++ /* Use the sector size and count of the cheat device */ ++ cheat_dev_size = grub_util_get_fd_size (dev->cheat_fd, dev->cheat, &cheat_log_sector_size); ++ if (cheat_dev_size == -1) ++ { ++ const char *errmsg = grub_util_fd_strerror (); ++ grub_util_fd_close (dev->cheat_fd); ++ dev->cheat_fd = GRUB_UTIL_FD_INVALID; ++ return grub_error (GRUB_ERR_IO, N_("failed to query size of device `%s': %s"), ++ dev->cheat, errmsg); ++ } ++ ++ dev->log_sector_size = cheat_log_sector_size; ++ dev->total_sectors = cheat_dev_size >> cheat_log_sector_size; + } + #endif + +@@ -721,6 +736,7 @@ grub_cryptodisk_open (const char *name, grub_disk_t disk) + } + + disk->data = dev; ++ disk->log_sector_size = dev->log_sector_size; + disk->total_sectors = dev->total_sectors; + disk->max_agglomerate = GRUB_DISK_MAX_MAX_AGGLOMERATE; + disk->id = dev->id; +-- +2.34.1 + diff --git a/0003-efi-tpm-Add-EFI_CC_MEASUREMENT_PROTOCOL-support.patch b/0003-efi-tpm-Add-EFI_CC_MEASUREMENT_PROTOCOL-support.patch new file mode 100644 index 0000000..ffe842f --- /dev/null +++ b/0003-efi-tpm-Add-EFI_CC_MEASUREMENT_PROTOCOL-support.patch @@ -0,0 +1,260 @@ +From 029c952f37dedb086c85bfb5fbc0de15cd4dbf0f Mon Sep 17 00:00:00 2001 +From: Lu Ken +Date: Wed, 13 Jul 2022 10:06:12 +0800 +Subject: [PATCH 3/3] efi/tpm: Add EFI_CC_MEASUREMENT_PROTOCOL support + +The EFI_CC_MEASUREMENT_PROTOCOL abstracts the measurement for virtual firmware +in confidential computing environment. It is similar to the EFI_TCG2_PROTOCOL. +It was proposed by Intel and ARM and approved by UEFI organization. + +It is defined in Intel GHCI specification: https://cdrdv2.intel.com/v1/dl/getContent/726790 . +The EDKII header file is available at https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Protocol/CcMeasurement.h . + +Signed-off-by: Lu Ken +Reviewed-by: Daniel Kiper +--- + grub-core/commands/efi/tpm.c | 48 +++++++++++ + include/grub/efi/cc.h | 151 +++++++++++++++++++++++++++++++++++ + 2 files changed, 199 insertions(+) + create mode 100644 include/grub/efi/cc.h + +diff --git a/grub-core/commands/efi/tpm.c b/grub-core/commands/efi/tpm.c +index e032617d8..630fd8a82 100644 +--- a/grub-core/commands/efi/tpm.c ++++ b/grub-core/commands/efi/tpm.c +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -32,6 +33,7 @@ typedef TCG_PCR_EVENT grub_tpm_event_t; + + static grub_efi_guid_t tpm_guid = EFI_TPM_GUID; + static grub_efi_guid_t tpm2_guid = EFI_TPM2_GUID; ++static grub_efi_guid_t cc_measurement_guid = GRUB_EFI_CC_MEASUREMENT_PROTOCOL_GUID; + + static grub_efi_handle_t *grub_tpm_handle; + static grub_uint8_t grub_tpm_version; +@@ -308,6 +310,50 @@ grub_tpm2_log_event (grub_efi_handle_t tpm_handle, unsigned char *buf, + return grub_efi_log_event_status (status); + } + ++static void ++grub_cc_log_event (unsigned char *buf, grub_size_t size, grub_uint8_t pcr, ++ const char *description) ++{ ++ grub_efi_cc_event_t *event; ++ grub_efi_status_t status; ++ grub_efi_cc_protocol_t *cc; ++ grub_efi_cc_mr_index_t mr; ++ ++ cc = grub_efi_locate_protocol (&cc_measurement_guid, NULL); ++ if (cc == NULL) ++ return; ++ ++ status = efi_call_3 (cc->map_pcr_to_mr_index, cc, pcr, &mr); ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_efi_log_event_status (status); ++ return; ++ } ++ ++ event = grub_zalloc (sizeof (grub_efi_cc_event_t) + ++ grub_strlen (description) + 1); ++ if (event == NULL) ++ { ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate CC event buffer")); ++ return; ++ } ++ ++ event->Header.HeaderSize = sizeof (grub_efi_cc_event_header_t); ++ event->Header.HeaderVersion = GRUB_EFI_CC_EVENT_HEADER_VERSION; ++ event->Header.MrIndex = mr; ++ event->Header.EventType = EV_IPL; ++ event->Size = sizeof (*event) + grub_strlen (description) + 1; ++ grub_strcpy ((char *) event->Event, description); ++ ++ status = efi_call_5 (cc->hash_log_extend_event, cc, 0, ++ (grub_efi_physical_address_t)(grub_addr_t) buf, ++ (grub_efi_uint64_t) size, event); ++ grub_free (event); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ grub_efi_log_event_status (status); ++} ++ + grub_err_t + grub_tpm_measure (unsigned char *buf, grub_size_t size, grub_uint8_t pcr, + const char *description) +@@ -315,6 +361,8 @@ grub_tpm_measure (unsigned char *buf, grub_size_t size, grub_uint8_t pcr, + grub_efi_handle_t tpm_handle; + grub_efi_uint8_t protocol_version; + ++ grub_cc_log_event(buf, size, pcr, description); ++ + if (!grub_tpm_handle_find (&tpm_handle, &protocol_version)) + return 0; + +diff --git a/include/grub/efi/cc.h b/include/grub/efi/cc.h +new file mode 100644 +index 000000000..896030689 +--- /dev/null ++++ b/include/grub/efi/cc.h +@@ -0,0 +1,151 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2022 Free Software Foundation, Inc. ++ * ++ * 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_EFI_CC_H ++#define GRUB_EFI_CC_H 1 ++ ++#include ++#include ++#include ++ ++#define GRUB_EFI_CC_MEASUREMENT_PROTOCOL_GUID \ ++ { 0x96751a3d, 0x72f4, 0x41a6, \ ++ { 0xa7, 0x94, 0xed, 0x5d, 0x0e, 0x67, 0xae, 0x6b } \ ++ }; ++ ++struct grub_efi_cc_version ++{ ++ grub_efi_uint8_t Major; ++ grub_efi_uint8_t Minor; ++}; ++typedef struct grub_efi_cc_version grub_efi_cc_version_t; ++ ++/* EFI_CC Type/SubType definition. */ ++#define GRUB_EFI_CC_TYPE_NONE 0 ++#define GRUB_EFI_CC_TYPE_SEV 1 ++#define GRUB_EFI_CC_TYPE_TDX 2 ++ ++struct grub_efi_cc_type ++{ ++ grub_efi_uint8_t Type; ++ grub_efi_uint8_t SubType; ++}; ++typedef struct grub_efi_cc_type grub_efi_cc_type_t; ++ ++typedef grub_efi_uint32_t grub_efi_cc_event_log_bitmap_t; ++typedef grub_efi_uint32_t grub_efi_cc_event_log_format_t; ++typedef grub_efi_uint32_t grub_efi_cc_event_algorithm_bitmap_t; ++typedef grub_efi_uint32_t grub_efi_cc_mr_index_t; ++ ++/* Intel TDX measure register index. */ ++#define GRUB_TDX_MR_INDEX_MRTD 0 ++#define GRUB_TDX_MR_INDEX_RTMR0 1 ++#define GRUB_TDX_MR_INDEX_RTMR1 2 ++#define GRUB_TDX_MR_INDEX_RTMR2 3 ++#define GRUB_TDX_MR_INDEX_RTMR3 4 ++ ++#define GRUB_EFI_CC_EVENT_LOG_FORMAT_TCG_2 0x00000002 ++#define GRUB_EFI_CC_BOOT_HASH_ALG_SHA384 0x00000004 ++#define GRUB_EFI_CC_EVENT_HEADER_VERSION 1 ++ ++struct grub_efi_cc_event_header ++{ ++ /* Size of the event header itself (sizeof(EFI_TD_EVENT_HEADER)). */ ++ grub_efi_uint32_t HeaderSize; ++ ++ /* ++ * Header version. For this version of this specification, ++ * the value shall be 1. ++ */ ++ grub_efi_uint16_t HeaderVersion; ++ ++ /* Index of the MR that shall be extended. */ ++ grub_efi_cc_mr_index_t MrIndex; ++ ++ /* Type of the event that shall be extended (and optionally logged). */ ++ grub_efi_uint32_t EventType; ++} GRUB_PACKED; ++typedef struct grub_efi_cc_event_header grub_efi_cc_event_header_t; ++ ++struct grub_efi_cc_event ++{ ++ /* Total size of the event including the Size component, the header and the Event data. */ ++ grub_efi_uint32_t Size; ++ grub_efi_cc_event_header_t Header; ++ grub_efi_uint8_t Event[0]; ++} GRUB_PACKED; ++typedef struct grub_efi_cc_event grub_efi_cc_event_t; ++ ++struct grub_efi_cc_boot_service_capability ++{ ++ /* Allocated size of the structure. */ ++ grub_efi_uint8_t Size; ++ ++ /* ++ * Version of the grub_efi_cc_boot_service_capability_t structure itself. ++ * For this version of the protocol, the Major version shall be set to 1 ++ * and the Minor version shall be set to 1. ++ */ ++ grub_efi_cc_version_t StructureVersion; ++ ++ /* ++ * Version of the EFI TD protocol. ++ * For this version of the protocol, the Major version shall be set to 1 ++ * and the Minor version shall be set to 1. ++ */ ++ grub_efi_cc_version_t ProtocolVersion; ++ ++ /* Supported hash algorithms. */ ++ grub_efi_cc_event_algorithm_bitmap_t HashAlgorithmBitmap; ++ ++ /* Bitmap of supported event log formats. */ ++ grub_efi_cc_event_log_bitmap_t SupportedEventLogs; ++ ++ /* Indicates the CC type. */ ++ grub_efi_cc_type_t CcType; ++}; ++typedef struct grub_efi_cc_boot_service_capability grub_efi_cc_boot_service_capability_t; ++ ++struct grub_efi_cc_protocol ++{ ++ grub_efi_status_t ++ (*get_capability) (struct grub_efi_cc_protocol *this, ++ grub_efi_cc_boot_service_capability_t *ProtocolCapability); ++ ++ grub_efi_status_t ++ (*get_event_log) (struct grub_efi_cc_protocol *this, ++ grub_efi_cc_event_log_format_t EventLogFormat, ++ grub_efi_physical_address_t *EventLogLocation, ++ grub_efi_physical_address_t *EventLogLastEntry, ++ grub_efi_boolean_t *EventLogTruncated); ++ ++ grub_efi_status_t ++ (*hash_log_extend_event) (struct grub_efi_cc_protocol *this, ++ grub_efi_uint64_t Flags, ++ grub_efi_physical_address_t DataToHash, ++ grub_efi_uint64_t DataToHashLen, ++ grub_efi_cc_event_t *EfiCcEvent); ++ ++ grub_efi_status_t ++ (*map_pcr_to_mr_index) (struct grub_efi_cc_protocol *this, ++ grub_efi_uint32_t PcrIndex, ++ grub_efi_cc_mr_index_t *MrIndex); ++}; ++typedef struct grub_efi_cc_protocol grub_efi_cc_protocol_t; ++ ++#endif +-- +2.35.3 + diff --git a/0003-ieee1275-change-the-logic-of-ieee1275_get_devargs.patch b/0003-ieee1275-change-the-logic-of-ieee1275_get_devargs.patch new file mode 100644 index 0000000..bc89763 --- /dev/null +++ b/0003-ieee1275-change-the-logic-of-ieee1275_get_devargs.patch @@ -0,0 +1,62 @@ +From 1729400ab816804a28ebf50cb1310607b2c4b75e Mon Sep 17 00:00:00 2001 +From: Diego Domingos +Date: Fri, 25 Feb 2022 12:49:51 -0500 +Subject: [PATCH 3/4] ieee1275: change the logic of ieee1275_get_devargs() + +Usually grub will parse the PFW arguments by searching for the first occurence of the character ':'. +However, we can have this char more than once on NQN. +This patch changes the logic to find the last occurence of this char so we can get the proper values +for NVMeoFC +--- + grub-core/kern/ieee1275/openfw.c | 21 ++++++++++++++++++++- + 1 file changed, 20 insertions(+), 1 deletion(-) + +diff --git a/grub-core/kern/ieee1275/openfw.c b/grub-core/kern/ieee1275/openfw.c +index f819bd106..655a71310 100644 +--- a/grub-core/kern/ieee1275/openfw.c ++++ b/grub-core/kern/ieee1275/openfw.c +@@ -354,6 +354,13 @@ static char * + grub_ieee1275_get_devargs (const char *path) + { + char *colon = grub_strchr (path, ':'); ++ char *colon_check = colon; ++ ++ /* Find the last occurence of colon */ ++ while(colon_check){ ++ colon = colon_check; ++ colon_check = grub_strchr (colon+1, ':'); ++ } + + if (! colon) + return 0; +@@ -368,6 +375,18 @@ grub_ieee1275_get_devname (const char *path) + char *colon = grub_strchr (path, ':'); + int pathlen = grub_strlen (path); + struct grub_ieee1275_devalias curalias; ++ ++ /* Check some special cases */ ++ if(grub_strstr(path, "nvme-of")){ ++ char *namespace_split = grub_strstr(path,"/namespace@"); ++ if(namespace_split){ ++ colon = grub_strchr (namespace_split, ':'); ++ } else { ++ colon = NULL; ++ } ++ ++ } ++ + if (colon) + pathlen = (int)(colon - path); + +@@ -693,7 +712,7 @@ grub_ieee1275_get_boot_dev (void) + return NULL; + } + +- bootpath = (char *) grub_malloc ((grub_size_t) bootpath_size + 64); ++ bootpath = (char *) grub_malloc ((grub_size_t) bootpath_size + 64 + 256); + if (! bootpath) + { + grub_print_error (); +-- +2.35.3 + diff --git a/0003-kern-efi-mm-Extract-function-to-add-memory-regions.patch b/0003-kern-efi-mm-Extract-function-to-add-memory-regions.patch new file mode 100644 index 0000000..e8cf6cd --- /dev/null +++ b/0003-kern-efi-mm-Extract-function-to-add-memory-regions.patch @@ -0,0 +1,86 @@ +From b4500ff77efe3b36256fae1e456ded65fd77cf04 Mon Sep 17 00:00:00 2001 +From: Patrick Steinhardt +Date: Thu, 21 Apr 2022 15:24:20 +1000 +Subject: [PATCH 3/5] kern/efi/mm: Extract function to add memory regions + +In preparation of support for runtime-allocating additional memory +region, this patch extracts the function to retrieve the EFI memory +map and add a subset of it to GRUB's own memory regions. + +Signed-off-by: Patrick Steinhardt +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +Tested-by: Patrick Steinhardt +--- + grub-core/kern/efi/mm.c | 21 +++++++++++++++------ + 1 file changed, 15 insertions(+), 6 deletions(-) + +diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c +index 2874522..087272f 100644 +--- a/grub-core/kern/efi/mm.c ++++ b/grub-core/kern/efi/mm.c +@@ -592,8 +592,8 @@ print_memory_map (grub_efi_memory_descriptor_t *memory_map, + } + #endif + +-void +-grub_efi_mm_init (void) ++static grub_err_t ++grub_efi_mm_add_regions (grub_size_t required_bytes) + { + grub_efi_memory_descriptor_t *memory_map; + grub_efi_memory_descriptor_t *memory_map_end; +@@ -606,7 +606,7 @@ grub_efi_mm_init (void) + /* Prepare a memory region to store two memory maps. */ + memory_map = grub_efi_allocate_any_pages (2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE)); + if (! memory_map) +- grub_fatal ("cannot allocate memory"); ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate memory for memory map"); + + /* Obtain descriptors for available memory. */ + map_size = MEMORY_MAP_SIZE; +@@ -624,14 +624,14 @@ grub_efi_mm_init (void) + + memory_map = grub_efi_allocate_any_pages (2 * BYTES_TO_PAGES (map_size)); + if (! memory_map) +- grub_fatal ("cannot allocate memory"); ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate memory for new memory map"); + + mm_status = grub_efi_get_memory_map (&map_size, memory_map, 0, + &desc_size, 0); + } + + if (mm_status < 0) +- grub_fatal ("cannot get memory map"); ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, "error fetching memory map from EFI"); + + memory_map_end = NEXT_MEMORY_DESCRIPTOR (memory_map, map_size); + +@@ -646,7 +646,7 @@ grub_efi_mm_init (void) + + /* Allocate memory regions for GRUB's memory management. */ + add_memory_regions (filtered_memory_map, desc_size, +- filtered_memory_map_end, BYTES_TO_PAGES (DEFAULT_HEAP_SIZE)); ++ filtered_memory_map_end, BYTES_TO_PAGES (required_bytes)); + + #if 0 + /* For debug. */ +@@ -664,6 +664,15 @@ grub_efi_mm_init (void) + /* Release the memory maps. */ + grub_efi_free_pages ((grub_addr_t) memory_map, + 2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE)); ++ ++ return GRUB_ERR_NONE; ++} ++ ++void ++grub_efi_mm_init (void) ++{ ++ if (grub_efi_mm_add_regions (DEFAULT_HEAP_SIZE) != GRUB_ERR_NONE) ++ grub_fatal ("%s", grub_errmsg); + } + + #if defined (__aarch64__) || defined (__arm__) || defined (__riscv) +-- +2.35.3 + 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/0004-kern-efi-mm-Pass-up-errors-from-add_memory_regions.patch b/0004-kern-efi-mm-Pass-up-errors-from-add_memory_regions.patch new file mode 100644 index 0000000..d2416a9 --- /dev/null +++ b/0004-kern-efi-mm-Pass-up-errors-from-add_memory_regions.patch @@ -0,0 +1,89 @@ +From 4287786dde414d9b0517d12762904b4b2be19d2a Mon Sep 17 00:00:00 2001 +From: Patrick Steinhardt +Date: Thu, 21 Apr 2022 15:24:21 +1000 +Subject: [PATCH 4/5] kern/efi/mm: Pass up errors from add_memory_regions() + +The function add_memory_regions() is currently only called on system +initialization to allocate a fixed amount of pages. As such, it didn't +need to return any errors: in case it failed, we cannot proceed anyway. +This will change with the upcoming support for requesting more memory +from the firmware at runtime, where it doesn't make sense anymore to +fail hard. + +Refactor the function to return an error to prepare for this. Note that +this does not change the behaviour when initializing the memory system +because grub_efi_mm_init() knows to call grub_fatal() in case +grub_efi_mm_add_regions() returns an error. + +Signed-off-by: Patrick Steinhardt +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +Tested-by: Patrick Steinhardt +--- + grub-core/kern/efi/mm.c | 22 +++++++++++++++------- + 1 file changed, 15 insertions(+), 7 deletions(-) + +diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c +index 087272f..45ea6d5 100644 +--- a/grub-core/kern/efi/mm.c ++++ b/grub-core/kern/efi/mm.c +@@ -514,7 +514,7 @@ filter_memory_map (grub_efi_memory_descriptor_t *memory_map, + } + + /* Add memory regions. */ +-static void ++static grub_err_t + add_memory_regions (grub_efi_memory_descriptor_t *memory_map, + grub_efi_uintn_t desc_size, + grub_efi_memory_descriptor_t *memory_map_end, +@@ -542,9 +542,9 @@ add_memory_regions (grub_efi_memory_descriptor_t *memory_map, + GRUB_EFI_ALLOCATE_ADDRESS, + GRUB_EFI_LOADER_CODE); + if (! addr) +- grub_fatal ("cannot allocate conventional memory %p with %u pages", +- (void *) ((grub_addr_t) start), +- (unsigned) pages); ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "Memory starting at %p (%u pages) marked as free, but EFI would not allocate", ++ (void *) ((grub_addr_t) start), (unsigned) pages); + + grub_mm_init_region (addr, PAGES_TO_BYTES (pages)); + +@@ -554,7 +554,11 @@ add_memory_regions (grub_efi_memory_descriptor_t *memory_map, + } + + if (required_pages > 0) +- grub_fatal ("too little memory"); ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "could not allocate all requested memory: %" PRIuGRUB_UINT64_T " pages still required after iterating EFI memory map", ++ required_pages); ++ ++ return GRUB_ERR_NONE; + } + + void +@@ -601,6 +605,7 @@ grub_efi_mm_add_regions (grub_size_t required_bytes) + grub_efi_memory_descriptor_t *filtered_memory_map_end; + grub_efi_uintn_t map_size; + grub_efi_uintn_t desc_size; ++ grub_err_t err; + int mm_status; + + /* Prepare a memory region to store two memory maps. */ +@@ -645,8 +650,11 @@ grub_efi_mm_add_regions (grub_size_t required_bytes) + sort_memory_map (filtered_memory_map, desc_size, filtered_memory_map_end); + + /* Allocate memory regions for GRUB's memory management. */ +- add_memory_regions (filtered_memory_map, desc_size, +- filtered_memory_map_end, BYTES_TO_PAGES (required_bytes)); ++ err = add_memory_regions (filtered_memory_map, desc_size, ++ filtered_memory_map_end, ++ BYTES_TO_PAGES (required_bytes)); ++ if (err != GRUB_ERR_NONE) ++ return err; + + #if 0 + /* For debug. */ +-- +2.35.3 + diff --git a/0004-normal-menu-Don-t-show-Booting-s-msg-when-auto-booti.patch b/0004-normal-menu-Don-t-show-Booting-s-msg-when-auto-booti.patch new file mode 100644 index 0000000..cdfbc7a --- /dev/null +++ b/0004-normal-menu-Don-t-show-Booting-s-msg-when-auto-booti.patch @@ -0,0 +1,93 @@ +From d4eb747f831d8b011c712f4335f12b572d6f32d9 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Fri, 28 Jan 2022 11:30:32 +0100 +Subject: [PATCH 04/10] normal/menu: Don't show "Booting `%s'" msg when + auto-booting with TIMEOUT_STYLE_HIDDEN + +When the user has asked the menu code to be hidden/quiet and the current +entry is being autobooted because the timeout has expired don't show +the "Booting `%s'" msg. + +This is necessary to let flicker-free boots really be flicker free, +otherwise the "Booting `%s'" msg will kick the EFI fb into text mode +and show the msg, breaking the flicker-free experience. + +Signed-off-by: Hans de Goede +--- + grub-core/normal/menu.c | 24 ++++++++++++++++-------- + 1 file changed, 16 insertions(+), 8 deletions(-) + +diff --git a/grub-core/normal/menu.c b/grub-core/normal/menu.c +index 47fc12551f..470bfc839b 100644 +--- a/grub-core/normal/menu.c ++++ b/grub-core/normal/menu.c +@@ -651,13 +651,15 @@ workaround_snapshot_menu_default_entry (grub_menu_t menu, const char *name, int + entry to be executed is a result of an automatic default selection because + of the timeout. */ + static int +-run_menu (grub_menu_t menu, int nested, int *auto_boot) ++run_menu (grub_menu_t menu, int nested, int *auto_boot, int *notify_boot) + { + grub_uint64_t saved_time; + int default_entry, current_entry; + int timeout; + enum timeout_style timeout_style; + ++ *notify_boot = 1; ++ + default_entry = get_entry_number (menu, "default"); + + workaround_snapshot_menu_default_entry (menu, "default", &default_entry); +@@ -734,6 +736,7 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot) + if (timeout == 0) + { + *auto_boot = 1; ++ *notify_boot = timeout_style != TIMEOUT_STYLE_HIDDEN; + return default_entry; + } + +@@ -894,12 +897,16 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot) + + /* Callback invoked immediately before a menu entry is executed. */ + static void +-notify_booting (grub_menu_entry_t entry, +- void *userdata __attribute__((unused))) ++notify_booting (grub_menu_entry_t entry, void *userdata) + { +- grub_printf (" "); +- grub_printf_ (N_("Booting `%s'"), entry->title); +- grub_printf ("\n\n"); ++ int *notify_boot = userdata; ++ ++ if (*notify_boot) ++ { ++ grub_printf (" "); ++ grub_printf_ (N_("Booting `%s'"), entry->title); ++ grub_printf ("\n\n"); ++ } + } + + /* Callback invoked when a default menu entry executed because of a timeout +@@ -947,8 +954,9 @@ show_menu (grub_menu_t menu, int nested, int autobooted) + int boot_entry; + grub_menu_entry_t e; + int auto_boot; ++ int notify_boot; + +- boot_entry = run_menu (menu, nested, &auto_boot); ++ boot_entry = run_menu (menu, nested, &auto_boot, ¬ify_boot); + if (boot_entry < 0) + break; + +@@ -960,7 +968,7 @@ show_menu (grub_menu_t menu, int nested, int autobooted) + + if (auto_boot) + grub_menu_execute_with_fallback (menu, e, autobooted, +- &execution_callback, 0); ++ &execution_callback, ¬ify_boot); + else + grub_menu_execute_entry (e, 0); + if (autobooted) +-- +2.34.1 + diff --git a/0004-ofpath-controller-name-update.patch b/0004-ofpath-controller-name-update.patch new file mode 100644 index 0000000..3ab01e5 --- /dev/null +++ b/0004-ofpath-controller-name-update.patch @@ -0,0 +1,28 @@ +From 7717cd9c27f18703287403af1a955588e3d0261f Mon Sep 17 00:00:00 2001 +From: mamatha +Date: Sat, 24 Sep 2022 11:22:39 +0530 +Subject: [PATCH 4/4] ofpath controller name update + +patch to update ofpath controller name + +Signed-off-by: mamatha +--- + grub-core/osdep/linux/ofpath.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/grub-core/osdep/linux/ofpath.c b/grub-core/osdep/linux/ofpath.c +index 212782d3f..7d31cfd0f 100644 +--- a/grub-core/osdep/linux/ofpath.c ++++ b/grub-core/osdep/linux/ofpath.c +@@ -483,6 +483,8 @@ of_path_get_nvmeof_adapter_info(char* sysfs_path, + buf3=strchr(buf2,'-')+1; + buf3=strchr(buf3,'-')+1; + nvmeof_info->target_wwpn = buf3; ++ buf3=strchr(buf3,'x')+1; ++ nvmeof_info->target_wwpn = buf3; + buf3 = strchr(nvmeof_info->target_wwpn,','); + *buf3 = '\0'; + +-- +2.35.3 + diff --git a/0005-EFI-suppress-the-Welcome-to-GRUB-message-in-EFI-buil.patch b/0005-EFI-suppress-the-Welcome-to-GRUB-message-in-EFI-buil.patch new file mode 100644 index 0000000..062fdf3 --- /dev/null +++ b/0005-EFI-suppress-the-Welcome-to-GRUB-message-in-EFI-buil.patch @@ -0,0 +1,45 @@ +From d9c7bfe88ce7391618192401c426c218d2a17795 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Fri, 28 Jan 2022 11:30:33 +0100 +Subject: [PATCH 05/10] EFI: suppress the "Welcome to GRUB!" message in EFI + builds + +Grub EFI builds are now often used in combination with flicker-free +boot, but this breaks with upstream grub because the "Welcome to GRUB!" +message will kick the EFI fb into text mode and show the msg, +breaking the flicker-free experience. + +EFI systems are so fast, that when the menu or the countdown are enabled +the message will be immediately overwritten, so in these cases not +printing the message does not matter. + +And in case when the timeout_style is set to TIMEOUT_STYLE_HIDDEN, +the user has asked grub to be quiet (for example to allow flickfree +boot) annd thus the message should not be printed. + +Signed-off-by: Hans de Goede +--- + grub-core/kern/main.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/grub-core/kern/main.c b/grub-core/kern/main.c +index 42ea96e39e..35dee404e8 100644 +--- a/grub-core/kern/main.c ++++ b/grub-core/kern/main.c +@@ -272,10 +272,13 @@ grub_main (void) + + grub_boot_time ("After machine init."); + ++ /* This breaks flicker-free boot on EFI systems, so disable it there. */ ++#ifndef GRUB_MACHINE_EFI + /* Hello. */ + grub_setcolorstate (GRUB_TERM_COLOR_HIGHLIGHT); + grub_printf ("Welcome to GRUB!\n\n"); + grub_setcolorstate (GRUB_TERM_COLOR_STANDARD); ++#endif + + #ifndef GRUB_MACHINE_PCBIOS + /* Init verifiers API. */ +-- +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/0005-kern-efi-mm-Implement-runtime-addition-of-pages.patch b/0005-kern-efi-mm-Implement-runtime-addition-of-pages.patch new file mode 100644 index 0000000..5790670 --- /dev/null +++ b/0005-kern-efi-mm-Implement-runtime-addition-of-pages.patch @@ -0,0 +1,77 @@ +From 3a2119e11b9c216f3b008a2c61aca52b91ad7547 Mon Sep 17 00:00:00 2001 +From: Patrick Steinhardt +Date: Thu, 21 Apr 2022 15:24:22 +1000 +Subject: [PATCH 5/5] kern/efi/mm: Implement runtime addition of pages + +Adjust the interface of grub_efi_mm_add_regions() to take a set of +GRUB_MM_ADD_REGION_* flags, which most notably is currently only the +GRUB_MM_ADD_REGION_CONSECUTIVE flag. This allows us to set the function +up as callback for the memory subsystem and have it call out to us in +case there's not enough pages available in the current heap. + +Signed-off-by: Patrick Steinhardt +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +Tested-by: Patrick Steinhardt +--- + grub-core/kern/efi/mm.c | 15 +++++++++++---- + 1 file changed, 11 insertions(+), 4 deletions(-) + +diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c +index 45ea6d5..48380d3 100644 +--- a/grub-core/kern/efi/mm.c ++++ b/grub-core/kern/efi/mm.c +@@ -518,7 +518,8 @@ static grub_err_t + add_memory_regions (grub_efi_memory_descriptor_t *memory_map, + grub_efi_uintn_t desc_size, + grub_efi_memory_descriptor_t *memory_map_end, +- grub_efi_uint64_t required_pages) ++ grub_efi_uint64_t required_pages, ++ unsigned int flags) + { + grub_efi_memory_descriptor_t *desc; + +@@ -532,6 +533,10 @@ add_memory_regions (grub_efi_memory_descriptor_t *memory_map, + + start = desc->physical_start; + pages = desc->num_pages; ++ ++ if (pages < required_pages && (flags & GRUB_MM_ADD_REGION_CONSECUTIVE)) ++ continue; ++ + if (pages > required_pages) + { + start += PAGES_TO_BYTES (pages - required_pages); +@@ -597,7 +602,7 @@ print_memory_map (grub_efi_memory_descriptor_t *memory_map, + #endif + + static grub_err_t +-grub_efi_mm_add_regions (grub_size_t required_bytes) ++grub_efi_mm_add_regions (grub_size_t required_bytes, unsigned int flags) + { + grub_efi_memory_descriptor_t *memory_map; + grub_efi_memory_descriptor_t *memory_map_end; +@@ -652,7 +657,8 @@ grub_efi_mm_add_regions (grub_size_t required_bytes) + /* Allocate memory regions for GRUB's memory management. */ + err = add_memory_regions (filtered_memory_map, desc_size, + filtered_memory_map_end, +- BYTES_TO_PAGES (required_bytes)); ++ BYTES_TO_PAGES (required_bytes), ++ flags); + if (err != GRUB_ERR_NONE) + return err; + +@@ -679,8 +685,9 @@ grub_efi_mm_add_regions (grub_size_t required_bytes) + void + grub_efi_mm_init (void) + { +- if (grub_efi_mm_add_regions (DEFAULT_HEAP_SIZE) != GRUB_ERR_NONE) ++ if (grub_efi_mm_add_regions (DEFAULT_HEAP_SIZE, GRUB_MM_ADD_REGION_NONE) != GRUB_ERR_NONE) + grub_fatal ("%s", grub_errmsg); ++ grub_mm_add_region_fn = grub_efi_mm_add_regions; + } + + #if defined (__aarch64__) || defined (__arm__) || defined (__riscv) +-- +2.35.3 + diff --git a/0006-EFI-console-Do-not-set-colorstate-until-the-first-te.patch b/0006-EFI-console-Do-not-set-colorstate-until-the-first-te.patch new file mode 100644 index 0000000..f556bc1 --- /dev/null +++ b/0006-EFI-console-Do-not-set-colorstate-until-the-first-te.patch @@ -0,0 +1,54 @@ +From 81339347bc10ec609227361434f75c5e36b85b9f Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Fri, 28 Jan 2022 12:43:48 +0100 +Subject: [PATCH 06/10] EFI: console: Do not set colorstate until the first + text output + +GRUB_MOD_INIT(normal) does an unconditional: + +grub_env_set ("color_normal", "light-gray/black"); + +which triggers a grub_term_setcolorstate() call. The original version +of the "efi/console: Do not set text-mode until we actually need it" patch: +https://lists.gnu.org/archive/html/grub-devel/2018-03/msg00125.html + +Protected against this by caching the requested state in +grub_console_setcolorstate () and then only applying it when the first +text output actually happens. During refactoring to move the +grub_console_setcolorstate () up higher in the grub-core/term/efi/console.c +file the code to cache the color-state + bail early was accidentally +dropped. + +Restore the cache the color-state + bail early behavior from the original. + +Cc: Javier Martinez Canillas +Fixes: 2d7c3abd871f ("efi/console: Do not set text-mode until we actually need it") +Signed-off-by: Hans de Goede +--- + grub-core/term/efi/console.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/grub-core/term/efi/console.c b/grub-core/term/efi/console.c +index 2f1ae85ba7..c44b2ac318 100644 +--- a/grub-core/term/efi/console.c ++++ b/grub-core/term/efi/console.c +@@ -82,6 +82,16 @@ grub_console_setcolorstate (struct grub_term_output *term + { + grub_efi_simple_text_output_interface_t *o; + ++ if (grub_efi_is_finished || text_mode != GRUB_TEXT_MODE_AVAILABLE) ++ { ++ /* ++ * Cache colorstate changes before the first text-output, this avoids ++ * "color_normal" environment writes causing a switch to textmode. ++ */ ++ text_colorstate = state; ++ return; ++ } ++ + if (grub_efi_is_finished) + return; + +-- +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-EFI-console-Do-not-set-cursor-until-the-first-text-o.patch b/0007-EFI-console-Do-not-set-cursor-until-the-first-text-o.patch new file mode 100644 index 0000000..531bec5 --- /dev/null +++ b/0007-EFI-console-Do-not-set-cursor-until-the-first-text-o.patch @@ -0,0 +1,75 @@ +From 9b12dc80d4254e22c41805cecf2494a8e6a50e3e Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Fri, 28 Jan 2022 12:43:49 +0100 +Subject: [PATCH 07/10] EFI: console: Do not set cursor until the first text + output + +To allow flickerfree boot the EFI console code does not call +grub_efi_set_text_mode (1) until some text is actually output. + +Depending on if the output text is because of an error loading +e.g. the .cfg file; or because of showing the menu the cursor needs +to be on or off when the first text is shown. + +So far the cursor was hardcoded to being on, but this is causing +drawing artifacts + slow drawing of the menu as reported here: +https://bugzilla.redhat.com/show_bug.cgi?id=1946969 + +Handle the cursorstate in the same way as the colorstate to fix this, +when no text has been output yet, just cache the cursorstate and +then use the last set value when the first text is output. + +Fixes: 2d7c3abd871f ("efi/console: Do not set text-mode until we actually need it") +Signed-off-by: Hans de Goede +--- + grub-core/term/efi/console.c | 19 ++++++++++++++++--- + 1 file changed, 16 insertions(+), 3 deletions(-) + +diff --git a/grub-core/term/efi/console.c b/grub-core/term/efi/console.c +index c44b2ac318..a3622e4fe5 100644 +--- a/grub-core/term/efi/console.c ++++ b/grub-core/term/efi/console.c +@@ -31,7 +31,15 @@ typedef enum { + } + grub_text_mode; + ++typedef enum { ++ GRUB_CURSOR_MODE_UNDEFINED = -1, ++ GRUB_CURSOR_MODE_OFF = 0, ++ GRUB_CURSUR_MODE_ON ++} ++grub_cursor_mode; ++ + static grub_text_mode text_mode = GRUB_TEXT_MODE_UNDEFINED; ++static grub_cursor_mode cursor_mode = GRUB_CURSOR_MODE_UNDEFINED; + static grub_term_color_state text_colorstate = GRUB_TERM_COLOR_UNDEFINED; + + static grub_uint32_t +@@ -119,8 +127,12 @@ grub_console_setcursor (struct grub_term_output *term __attribute__ ((unused)), + { + grub_efi_simple_text_output_interface_t *o; + +- if (grub_efi_is_finished) +- return; ++ if (grub_efi_is_finished || text_mode != GRUB_TEXT_MODE_AVAILABLE) ++ { ++ /* Cache cursor changes before the first text-output */ ++ cursor_mode = on; ++ return; ++ } + + o = grub_efi_system_table->con_out; + efi_call_2 (o->enable_cursor, o, on); +@@ -143,7 +155,8 @@ grub_prepare_for_text_output (struct grub_term_output *term) + return GRUB_ERR_BAD_DEVICE; + } + +- grub_console_setcursor (term, 1); ++ if (cursor_mode != GRUB_CURSOR_MODE_UNDEFINED) ++ grub_console_setcursor (term, cursor_mode); + if (text_colorstate != GRUB_TERM_COLOR_UNDEFINED) + grub_console_setcolorstate (term, text_colorstate); + text_mode = GRUB_TEXT_MODE_AVAILABLE; +-- +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/0008-linuxefi-Use-common-grub_initrd_load.patch b/0008-linuxefi-Use-common-grub_initrd_load.patch new file mode 100644 index 0000000..2f0209e --- /dev/null +++ b/0008-linuxefi-Use-common-grub_initrd_load.patch @@ -0,0 +1,156 @@ +From adf486860fe0d395579be8b01d4fda8b93377768 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Wed, 8 Jun 2022 16:04:12 +0800 +Subject: [PATCH 08/10] linuxefi: Use common grub_initrd_load + +By using the common initrd loading routine factored out allows to share between +features like concatenating initramfs component. + +For eg. + + initrdefi /initrd-5.16.15-1-default newc:grub.cfg:/grub2/grub.cfg + +The file /grub2/grub.cfg read off from root disk will be available to use as +/grub.cfg in the target initramfs loaded by grub. + +Signed-off-by: Michael Chang +--- + grub-core/loader/i386/efi/linux.c | 87 ++++--------------------------- + 1 file changed, 10 insertions(+), 77 deletions(-) + +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index 6b06a8f2ff..f93395fc62 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -30,6 +30,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -146,44 +147,6 @@ grub_linuxefi_unload (void) + return GRUB_ERR_NONE; + } + +-#define BOUNCE_BUFFER_MAX 0x1000000ull +- +-static grub_ssize_t +-read(grub_file_t file, grub_uint8_t *bufp, grub_size_t len) +-{ +- grub_ssize_t bufpos = 0; +- static grub_size_t bbufsz = 0; +- static char *bbuf = NULL; +- +- if (bbufsz == 0) +- bbufsz = MIN(BOUNCE_BUFFER_MAX, len); +- +- while (!bbuf && bbufsz) +- { +- bbuf = grub_malloc(bbufsz); +- if (!bbuf) +- bbufsz >>= 1; +- } +- if (!bbuf) +- grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate bounce buffer")); +- +- while (bufpos < (long long)len) +- { +- grub_ssize_t sz; +- +- sz = grub_file_read (file, bbuf, MIN(bbufsz, len - bufpos)); +- if (sz < 0) +- return sz; +- if (sz == 0) +- break; +- +- grub_memcpy(bufp + bufpos, bbuf, sz); +- bufpos += sz; +- } +- +- return bufpos; +-} +- + #define LOW_U32(val) ((grub_uint32_t)(((grub_addr_t)(val)) & 0xffffffffull)) + #define HIGH_U32(val) ((grub_uint32_t)(((grub_addr_t)(val) >> 32) & 0xffffffffull)) + +@@ -191,10 +154,8 @@ static grub_err_t + grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) + { +- grub_file_t *files = 0; +- int i, nfiles = 0; ++ struct grub_linux_initrd_context initrd_ctx = { 0, 0, 0 }; + grub_size_t size = 0; +- grub_uint8_t *ptr; + + if (argc == 0) + { +@@ -208,24 +169,10 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + goto fail; + } + +- files = grub_calloc (argc, sizeof (files[0])); +- if (!files) ++ if (grub_initrd_init (argc, argv, &initrd_ctx)) + goto fail; + +- for (i = 0; i < argc; i++) +- { +- files[i] = grub_file_open (argv[i], GRUB_FILE_TYPE_LINUX_INITRD +- | GRUB_FILE_TYPE_NO_DECOMPRESS); +- if (! files[i]) +- goto fail; +- nfiles++; +- if (grub_add (size, ALIGN_UP (grub_file_size (files[i]), 4), &size)) +- { +- grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow is detected")); +- goto fail; +- } +- } +- ++ size = grub_get_initrd_size (&initrd_ctx); + initrd_mem = kernel_alloc(size, N_("can't allocate initrd")); + if (initrd_mem == NULL) + goto fail; +@@ -238,30 +185,16 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + params->ext_ramdisk_image = HIGH_U32(initrd_mem); + #endif + +- ptr = initrd_mem; +- +- for (i = 0; i < nfiles; i++) +- { +- grub_ssize_t cursize = grub_file_size (files[i]); +- if (read (files[i], ptr, cursize) != cursize) +- { +- if (!grub_errno) +- grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"), +- argv[i]); +- goto fail; +- } +- ptr += cursize; +- grub_memset (ptr, 0, ALIGN_UP_OVERHEAD (cursize, 4)); +- ptr += ALIGN_UP_OVERHEAD (cursize, 4); +- } ++ /* FIXME: Use bounce buffers as many UEFI machines apparently can't DMA ++ * correctly above 4GB ++ */ ++ if (grub_initrd_load (&initrd_ctx, argv, initrd_mem)) ++ goto fail; + + params->ramdisk_size = size; + + fail: +- for (i = 0; i < nfiles; i++) +- grub_file_close (files[i]); +- grub_free (files); +- ++ grub_initrd_close (&initrd_ctx); + if (initrd_mem && grub_errno) + grub_efi_free_pages((grub_efi_physical_address_t)(grub_addr_t)initrd_mem, BYTES_TO_PAGES(size)); + +-- +2.34.1 + diff --git a/0009-Add-crypttab_entry-to-obviate-the-need-to-input-pass.patch b/0009-Add-crypttab_entry-to-obviate-the-need-to-input-pass.patch new file mode 100644 index 0000000..f0fef49 --- /dev/null +++ b/0009-Add-crypttab_entry-to-obviate-the-need-to-input-pass.patch @@ -0,0 +1,328 @@ +From 749f7dee6f63217e536663aebb817aec72a65d5a Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Thu, 9 Jun 2022 21:06:00 +0800 +Subject: [PATCH 09/10] Add crypttab_entry to obviate the need to input + password twice + +This patch adds crypttab_entry command to hint grub where to put the key file +automatically loaded by linux cryptsetup. It's syntax is similar to +/etc/crypttab so that it is relatively straightforward to import. + + crypttab_entry + +For eg: + + crypttab_entry cr_root 5e1dd109e39343f984da57fd742d3f23 none + +Please note the "encrypted-device" only accepts UUID without dashes as it is +the only identification used by grub's cryptodisk device. The crypttab_entry +can also be used multiple times to specify encrypted volumes unlocked by +"cryptomount -a". + +Signed-off-by: Michael Chang +--- + grub-core/Makefile.core.def | 5 + + grub-core/commands/crypttab.c | 42 ++++++++++++ + grub-core/disk/cryptodisk.c | 6 + + grub-core/loader/linux.c | 137 ++++++++++++++++++++++++++++++++++++++++-- + include/grub/linux.h | 3 + 5 files changed, 188 insertions(+), 5 deletions(-) + create mode 100644 grub-core/commands/crypttab.c + +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -2643,3 +2643,8 @@ + cflags = '$(CFLAGS_POSIX) $(CFLAGS_GNULIB)'; + cppflags = '$(CPPFLAGS_POSIX) $(CPPFLAGS_GNULIB)'; + }; ++ ++module = { ++ name = crypttab; ++ common = commands/crypttab.c; ++}; +--- /dev/null ++++ b/grub-core/commands/crypttab.c +@@ -0,0 +1,42 @@ ++ ++#include ++#include ++#include ++#include ++#include ++ ++GRUB_MOD_LICENSE ("GPLv3+"); ++ ++static grub_err_t ++grub_cmd_crypttab_entry (grub_command_t cmd __attribute__ ((unused)), ++ int argc, char **argv) ++{ ++ char buf[64]; ++ const char *path = argv[2]; ++ ++ if (argc != 3) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("three arguments expected")); ++ ++ if (grub_strcmp (argv[2], "none") == 0 ++ || grub_strcmp (argv[2], "-") == 0) ++ { ++ grub_snprintf (buf, sizeof (buf), "/etc/cryptsetup-keys.d/%s.key", argv[0]); ++ path = buf; ++ } ++ ++ /*FIXME: Validate UUID string*/ ++ return grub_initrd_publish_key (argv[1], NULL, 0, path); ++} ++ ++static grub_command_t cmd; ++ ++GRUB_MOD_INIT(crypttab) ++{ ++ cmd = grub_register_command ("crypttab_entry", grub_cmd_crypttab_entry, ++ N_("VOLUME-NAME ENCRYPTED-DEVICE KEY-FILE") , N_("No description")); ++} ++ ++GRUB_MOD_FINI(crypttab) ++{ ++ grub_unregister_command (cmd); ++} +--- a/grub-core/disk/cryptodisk.c ++++ b/grub-core/disk/cryptodisk.c +@@ -30,6 +30,8 @@ + + #ifdef GRUB_UTIL + #include ++#else ++#include + #endif + + GRUB_MOD_LICENSE ("GPLv3+"); +@@ -1146,6 +1148,10 @@ + dev = NULL; + + cleanup: ++#ifndef GRUB_UTIL ++ if (cargs->key_data && dev) ++ grub_initrd_publish_key (dev->uuid, (const char *)cargs->key_data, cargs->key_len, NULL); ++#endif + if (askpass) + { + cargs->key_len = 0; +--- a/grub-core/loader/linux.c ++++ b/grub-core/loader/linux.c +@@ -5,6 +5,7 @@ + #include + #include + #include ++#include + + struct newc_head + { +@@ -27,6 +28,7 @@ + struct grub_linux_initrd_component + { + grub_file_t file; ++ char *buf; + char *newc_name; + grub_off_t size; + }; +@@ -38,6 +40,18 @@ + struct dir *child; + }; + ++struct grub_key_publisher ++{ ++ struct grub_key_publisher *next; ++ struct grub_key_publisher **prev; ++ char *name; /* UUID */ ++ char *path; ++ char *key; ++ grub_size_t key_len; ++}; ++ ++static struct grub_key_publisher *kpuber; ++ + static char + hex (grub_uint8_t val) + { +@@ -149,6 +163,65 @@ + return GRUB_ERR_NONE; + } + ++static grub_err_t ++grub_initrd_component (const char *buf, int bufsz, const char *newc_name, ++ struct grub_linux_initrd_context *initrd_ctx) ++{ ++ struct dir *root = 0; ++ struct grub_linux_initrd_component *comp = initrd_ctx->components + initrd_ctx->nfiles; ++ grub_size_t dir_size, name_len; ++ ++ while (*newc_name == '/') ++ newc_name++; ++ ++ initrd_ctx->size = ALIGN_UP (initrd_ctx->size, 4); ++ comp->newc_name = grub_strdup (newc_name); ++ if (!comp->newc_name || ++ insert_dir (comp->newc_name, &root, 0, &dir_size)) ++ { ++ /* FIXME: Check NULL file pointer before close */ ++ grub_initrd_close (initrd_ctx); ++ return grub_errno; ++ } ++ /* Should name_len count terminating null ? */ ++ name_len = grub_strlen (comp->newc_name) + 1; ++ if (grub_add (initrd_ctx->size, ++ ALIGN_UP (sizeof (struct newc_head) + name_len, 4), ++ &initrd_ctx->size) || ++ grub_add (initrd_ctx->size, dir_size, &initrd_ctx->size)) ++ goto overflow; ++ ++ comp->buf = grub_malloc (bufsz); ++ if (!comp->buf) ++ { ++ free_dir (root); ++ grub_initrd_close (initrd_ctx); ++ return grub_errno; ++ } ++ grub_memcpy (comp->buf, buf, bufsz); ++ initrd_ctx->nfiles++; ++ comp->size = bufsz; ++ if (grub_add (initrd_ctx->size, comp->size, ++ &initrd_ctx->size)) ++ goto overflow; ++ ++ initrd_ctx->size = ALIGN_UP (initrd_ctx->size, 4); ++ if (grub_add (initrd_ctx->size, ++ ALIGN_UP (sizeof (struct newc_head) ++ + sizeof ("TRAILER!!!") - 1, 4), ++ &initrd_ctx->size)) ++ goto overflow; ++ ++ free_dir (root); ++ root = 0; ++ return GRUB_ERR_NONE; ++ ++ overflow: ++ free_dir (root); ++ grub_initrd_close (initrd_ctx); ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow is detected")); ++} ++ + grub_err_t + grub_initrd_init (int argc, char *argv[], + struct grub_linux_initrd_context *initrd_ctx) +@@ -156,11 +229,17 @@ + int i; + int newc = 0; + struct dir *root = 0; ++ struct grub_key_publisher *pk; ++ int numkey = 0; + + initrd_ctx->nfiles = 0; + initrd_ctx->components = 0; + +- initrd_ctx->components = grub_calloc (argc, sizeof (initrd_ctx->components[0])); ++ FOR_LIST_ELEMENTS (pk, kpuber) ++ if (pk->key && pk->path) ++ numkey++; ++ ++ initrd_ctx->components = grub_calloc (argc + numkey, sizeof (initrd_ctx->components[0])); + if (!initrd_ctx->components) + return grub_errno; + +@@ -239,7 +318,10 @@ + free_dir (root); + root = 0; + } +- ++ ++ FOR_LIST_ELEMENTS (pk, kpuber) ++ if (pk->key && pk->path) ++ grub_initrd_component (pk->key, pk->key_len, pk->path, initrd_ctx); + return GRUB_ERR_NONE; + + overflow: +@@ -263,7 +345,9 @@ + for (i = 0; i < initrd_ctx->nfiles; i++) + { + grub_free (initrd_ctx->components[i].newc_name); +- grub_file_close (initrd_ctx->components[i].file); ++ if (initrd_ctx->components[i].file) ++ grub_file_close (initrd_ctx->components[i].file); ++ grub_free (initrd_ctx->components[i].buf); + } + grub_free (initrd_ctx->components); + initrd_ctx->components = 0; +@@ -297,7 +381,7 @@ + } + ptr += dir_size; + ptr = make_header (ptr, initrd_ctx->components[i].newc_name, +- grub_strlen (initrd_ctx->components[i].newc_name), ++ grub_strlen (initrd_ctx->components[i].newc_name) + 1, + 0100777, + initrd_ctx->components[i].size); + newc = 1; +@@ -312,7 +396,12 @@ + } + + cursize = initrd_ctx->components[i].size; +- if (grub_file_read (initrd_ctx->components[i].file, ptr, cursize) ++ if (initrd_ctx->components[i].buf) ++ { ++ grub_memcpy (ptr, initrd_ctx->components[i].buf, cursize); ++ newc = 1; ++ } ++ else if (grub_file_read (initrd_ctx->components[i].file, ptr, cursize) + != cursize) + { + if (!grub_errno) +@@ -333,3 +422,41 @@ + root = 0; + return GRUB_ERR_NONE; + } ++ ++grub_err_t ++grub_initrd_publish_key (const char *uuid, const char *key, grub_size_t key_len, const char *path) ++{ ++ struct grub_key_publisher *cur = grub_named_list_find (GRUB_AS_NAMED_LIST (kpuber), uuid); ++ ++ if (!cur) ++ cur = grub_zalloc (sizeof (*cur)); ++ if (!cur) ++ return grub_errno; ++ ++ if (key && key_len) ++ { ++ grub_free (cur->key); ++ cur->key = grub_malloc (key_len); ++ if (!cur->key) ++ { ++ grub_free (cur); ++ return grub_errno; ++ } ++ grub_memcpy (cur->key, key, key_len); ++ cur->key_len = key_len; ++ } ++ ++ if (path) ++ { ++ grub_free (cur->path); ++ cur->path = grub_strdup (path); ++ } ++ ++ if (!cur->name) ++ { ++ cur->name = grub_strdup (uuid); ++ grub_list_push (GRUB_AS_LIST_P (&kpuber), GRUB_AS_LIST (cur)); ++ } ++ ++ return GRUB_ERR_NONE; ++} +--- a/include/grub/linux.h ++++ b/include/grub/linux.h +@@ -22,3 +22,6 @@ + grub_err_t + grub_initrd_load (struct grub_linux_initrd_context *initrd_ctx, + char *argv[], void *target); ++ ++grub_err_t ++grub_initrd_publish_key (const char *uuid, const char *key, grub_size_t key_len, const char *path); 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/0010-templates-import-etc-crypttab-to-grub.cfg.patch b/0010-templates-import-etc-crypttab-to-grub.cfg.patch new file mode 100644 index 0000000..b181685 --- /dev/null +++ b/0010-templates-import-etc-crypttab-to-grub.cfg.patch @@ -0,0 +1,81 @@ +From 2d3130c289b293269dcf558a26674f83f77729a6 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Tue, 14 Jun 2022 17:10:01 +0800 +Subject: [PATCH 10/10] templates: import /etc/crypttab to grub.cfg + +The /etc/crypptab is used to setup location of encryption key files during +boot, among other things. It is useful to make use the information by grub to +determine where keys are being looked up. + +This script can be used to import relevant /etc/crypptab entry to grub.cfg. + +Signed-off-by: Michael Chang +--- + Makefile.util.def | 7 +++++++ + util/grub.d/05_crypttab.in | 36 ++++++++++++++++++++++++++++++++++++ + 2 files changed, 43 insertions(+) + create mode 100644 util/grub.d/05_crypttab.in + +diff --git a/Makefile.util.def b/Makefile.util.def +index 08f681cd8b..5e0ba22f3d 100644 +--- a/Makefile.util.def ++++ b/Makefile.util.def +@@ -476,6 +476,13 @@ script = { + installdir = grubconf; + }; + ++script = { ++ name = '05_crypttab'; ++ common = util/grub.d/05_crypttab.in; ++ installdir = grubconf; ++ condition = COND_HOST_LINUX; ++}; ++ + script = { + name = '10_windows'; + common = util/grub.d/10_windows.in; +diff --git a/util/grub.d/05_crypttab.in b/util/grub.d/05_crypttab.in +new file mode 100644 +index 0000000000..c539bc061e +--- /dev/null ++++ b/util/grub.d/05_crypttab.in +@@ -0,0 +1,36 @@ ++#! /bin/sh ++set -e ++ ++# grub-mkconfig helper script. ++# Copyright (C) 2022 Free Software Foundation, Inc. ++# ++# 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 . ++ ++prefix="@prefix@" ++exec_prefix="@exec_prefix@" ++datarootdir="@datarootdir@" ++ ++export TEXTDOMAIN=@PACKAGE@ ++export TEXTDOMAINDIR="@localedir@" ++ ++. "$pkgdatadir/grub-mkconfig_lib" ++ ++CRYPTTAB=/etc/crypttab ++ ++if [ -r "$CRYPTTAB" ]; then ++ awk '/UUID=/ { sub(/UUID=/,"",$2); \ ++ gsub(/-/,"",$2); \ ++ printf("crypttab_entry %s %s %s\n",$1,$2,$3) \ ++ }' "$CRYPTTAB" ++fi +-- +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/efi-set-variable-with-attrs.patch b/efi-set-variable-with-attrs.patch new file mode 100644 index 0000000..d2959d0 --- /dev/null +++ b/efi-set-variable-with-attrs.patch @@ -0,0 +1,51 @@ +Index: grub-2.06/include/grub/efi/efi.h +=================================================================== +--- grub-2.06.orig/include/grub/efi/efi.h ++++ grub-2.06/include/grub/efi/efi.h +@@ -86,6 +86,11 @@ grub_efi_status_t EXPORT_FUNC (grub_efi_ + const grub_efi_guid_t *guid, + grub_size_t *datasize_out, + void **data_out); ++grub_err_t EXPORT_FUNC (grub_efi_set_variable_with_attributes) (const char *var, ++ const grub_efi_guid_t *guid, ++ grub_efi_uint32_t attributes, ++ void *data, ++ grub_size_t datasize); + grub_err_t + EXPORT_FUNC (grub_efi_set_variable) (const char *var, + const grub_efi_guid_t *guid, +Index: grub-2.06/grub-core/kern/efi/efi.c +=================================================================== +--- grub-2.06.orig/grub-core/kern/efi/efi.c ++++ grub-2.06/grub-core/kern/efi/efi.c +@@ -196,6 +196,17 @@ grub_err_t + grub_efi_set_variable(const char *var, const grub_efi_guid_t *guid, + void *data, grub_size_t datasize) + { ++ return grub_efi_set_variable_with_attributes(var, guid, ++ (GRUB_EFI_VARIABLE_NON_VOLATILE ++ | GRUB_EFI_VARIABLE_BOOTSERVICE_ACCESS ++ | GRUB_EFI_VARIABLE_RUNTIME_ACCESS), ++ data, datasize); ++} ++ ++grub_err_t ++grub_efi_set_variable_with_attributes(const char *var, const grub_efi_guid_t *guid, grub_efi_uint32_t attributes, ++ void *data, grub_size_t datasize) ++{ + grub_efi_status_t status; + grub_efi_runtime_services_t *r; + grub_efi_char16_t *var16; +@@ -211,10 +222,8 @@ grub_efi_set_variable(const char *var, c + + r = grub_efi_system_table->runtime_services; + +- status = efi_call_5 (r->set_variable, var16, guid, +- (GRUB_EFI_VARIABLE_NON_VOLATILE +- | GRUB_EFI_VARIABLE_BOOTSERVICE_ACCESS +- | GRUB_EFI_VARIABLE_RUNTIME_ACCESS), ++ status = efi_call_5 (r->set_variable, var16, guid, ++ attributes, + datasize, data); + grub_free (var16); + if (status == GRUB_EFI_SUCCESS) 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/grub-install-record-pcrs.patch b/grub-install-record-pcrs.patch new file mode 100644 index 0000000..97ea0a1 --- /dev/null +++ b/grub-install-record-pcrs.patch @@ -0,0 +1,18 @@ +Index: grub-2.06/util/grub-install.c +=================================================================== +--- grub-2.06.orig/util/grub-install.c ++++ grub-2.06/util/grub-install.c +@@ -1457,6 +1457,13 @@ main (int argc, char *argv[]) + + grub_util_unlink (load_cfg); + ++ if (1) ++ { ++ load_cfg_f = grub_util_fopen (load_cfg, "wb"); ++ have_load_cfg = 1; ++ fprintf (load_cfg_f, "tpm_record_pcrs 0-9\n"); ++ } ++ + if (debug_image && debug_image[0]) + { + load_cfg_f = grub_util_fopen (load_cfg, "wb"); diff --git a/grub-read-pcr.patch b/grub-read-pcr.patch new file mode 100644 index 0000000..c4d0fa3 --- /dev/null +++ b/grub-read-pcr.patch @@ -0,0 +1,151 @@ +Index: grub-2.06/include/grub/tpm.h +=================================================================== +--- grub-2.06.orig/include/grub/tpm.h ++++ grub-2.06/include/grub/tpm.h +@@ -34,6 +34,15 @@ + + #define EV_IPL 0x0d + ++struct grub_tpm_digest { ++ const char * algorithm; ++ unsigned int size; ++ unsigned char value[1]; /* variable length */ ++}; ++ + grub_err_t grub_tpm_measure (unsigned char *buf, grub_size_t size, + grub_uint8_t pcr, const char *description); ++struct grub_tpm_digest *grub_tpm_read_pcr (grub_uint8_t index, const char *algo); ++void grub_tpm_digest_free (struct grub_tpm_digest *d); ++ + #endif +Index: grub-2.06/grub-core/commands/efi/tpm.c +=================================================================== +--- grub-2.06.orig/grub-core/commands/efi/tpm.c ++++ grub-2.06/grub-core/commands/efi/tpm.c +@@ -23,6 +23,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -186,6 +187,91 @@ grub_tpm1_log_event (grub_efi_handle_t t + return grub_efi_log_event_status (status); + } + ++static void ++grub_tpm2_select_pcr(TPML_PCR_SELECTION *o, unsigned int pcrIndex, unsigned int algo) ++{ ++ TPMS_PCR_SELECTION *pcr; ++ ++ pcr = &o->pcrSelections[o->count++]; ++ pcr->hash = algo; ++ pcr->sizeOfSelect = 3; ++ pcr->pcrSelect[TPM2_PCR_TO_SELECT(pcrIndex)] |= TPM2_PCR_TO_BIT(pcrIndex); ++} ++ ++struct grub_tpm_hash_info { ++ const char *name; ++ grub_size_t size; ++ int id; ++}; ++ ++static const struct grub_tpm_hash_info * ++grub_tpm2_get_digest_info (const char *algo) ++{ ++ static struct grub_tpm_hash_info __hashes[] = { ++ { "sha256", 32, TPM_ALG_SHA256 }, /* first entry is the default */ ++ { "sha512", 64, TPM_ALG_SHA512 }, ++ { "sha1", 20, TPM_ALG_SHA1 }, ++ { NULL } ++ }; ++ struct grub_tpm_hash_info *h; ++ ++ if (algo == NULL) ++ return &__hashes[0]; ++ ++ for (h = __hashes; h->name; ++h) ++ if (!grub_strcmp(h->name, algo)) ++ return h; ++ ++ return NULL; ++} ++ ++static grub_err_t ++grub_tpm2_read_pcr (grub_int8_t pcrIndex, const char *algo, struct grub_tpm_digest **ret) ++{ ++ const struct grub_tpm_hash_info *info; ++ TPML_PCR_SELECTION inSelection, outSelection; ++ grub_uint32_t pcrUpdateCounter; ++ TPML_DIGEST digests = { 0 }; ++ TPM2B_DIGEST *d; ++ struct grub_tpm_digest *result; ++ int rc; ++ ++ info = grub_tpm2_get_digest_info (algo); ++ if (info == NULL) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Unknown digest algorithm %s"), algo); ++ ++ grub_memset(&inSelection, 0, sizeof(inSelection)); ++ grub_memset(&outSelection, 0, sizeof(outSelection)); ++ grub_tpm2_select_pcr(&inSelection, pcrIndex, info->id); ++ ++ rc = TPM2_PCR_Read( ++ NULL, ++ &inSelection, ++ &pcrUpdateCounter, ++ &outSelection, ++ &digests, ++ NULL ++ ); ++ ++ if (rc != 0) ++ return grub_error (GRUB_ERR_BAD_DEVICE, "TPM2_PCR_Read failed, status=%d", rc); ++ ++ d = &digests.digests[0]; ++ ++ *ret = result = grub_malloc (sizeof (*result) + d->size); ++ grub_memcpy (result->value, d->buffer, d->size); ++ result->algorithm = info->name; ++ result->size = d->size; ++ ++ return GRUB_ERR_NONE; ++} ++ ++void ++grub_tpm_digest_free (struct grub_tpm_digest *d) ++{ ++ grub_free (d); ++} ++ + static grub_err_t + grub_tpm2_log_event (grub_efi_handle_t tpm_handle, unsigned char *buf, + grub_size_t size, grub_uint8_t pcr, +@@ -240,3 +326,26 @@ grub_tpm_measure (unsigned char *buf, gr + else + return grub_tpm2_log_event (tpm_handle, buf, size, pcr, description); + } ++ ++struct grub_tpm_digest * ++grub_tpm_read_pcr (grub_uint8_t pcr, const char *algo) ++{ ++ grub_efi_handle_t tpm_handle; ++ grub_efi_uint8_t protocol_version; ++ struct grub_tpm_digest *result = NULL; ++ ++ ++ if (!grub_tpm_handle_find (&tpm_handle, &protocol_version)) ++ return 0; ++ ++ if (protocol_version != 2) ++ { ++ grub_error (GRUB_ERR_BAD_DEVICE, N_("%s: TPM version %d not implemented"), __func__, protocol_version); ++ return NULL; ++ } ++ ++ if (grub_tpm2_read_pcr (pcr, algo, &result)) ++ return NULL; ++ ++ return result; ++} diff --git a/grub-unseal-debug.patch b/grub-unseal-debug.patch new file mode 100644 index 0000000..2d9225b --- /dev/null +++ b/grub-unseal-debug.patch @@ -0,0 +1,41 @@ +Index: grub-2.06/grub-core/tpm2/module.c +=================================================================== +--- grub-2.06.orig/grub-core/tpm2/module.c ++++ grub-2.06/grub-core/tpm2/module.c +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -449,6 +450,7 @@ grub_tpm2_protector_srk_recover (const s + { + grub_error (err, N_("Failed to unseal sealed key (TPM2_Unseal failed " + "with TSS/TPM error %u)"), rc); ++ grub_millisleep(500); + goto exit4; + } + +@@ -461,6 +463,8 @@ grub_tpm2_protector_srk_recover (const s + goto exit4; + } + ++ grub_printf("TPM2: unsealed %u bytes of key material\n", data.size); ++ + if (ctx->efivar) + { + rc = grub_tpm2_protector_publish_key (data.buffer, data.size, ctx->efivar); +Index: grub-2.06/grub-core/loader/linux.c +=================================================================== +--- grub-2.06.orig/grub-core/loader/linux.c ++++ grub-2.06/grub-core/loader/linux.c +@@ -171,6 +171,7 @@ grub_initrd_component (const char *buf, + struct grub_linux_initrd_component *comp = initrd_ctx->components + initrd_ctx->nfiles; + grub_size_t dir_size, name_len; + ++ grub_printf("Creating initrd component \"%s\" with %u bytes\n", newc_name, bufsz); + while (*newc_name == '/') + newc_name++; + diff --git a/grub2.changes b/grub2.changes index c7b5a0f..985e158 100644 --- a/grub2.changes +++ b/grub2.changes @@ -1,3 +1,137 @@ +------------------------------------------------------------------- +Fri Oct 28 04:58:28 UTC 2022 - Michael Chang + +- NVMeoFC support on grub (jsc#PED-996) + * 0001-ieee1275-add-support-for-NVMeoFC.patch + * 0002-ieee1275-ofpath-enable-NVMeoF-logical-device-transla.patch + * 0003-ieee1275-change-the-logic-of-ieee1275_get_devargs.patch + * 0004-ofpath-controller-name-update.patch +- TDX: Enhance grub2 measurement to TD RTMR (jsc#PED-1265) + * 0001-commands-efi-tpm-Refine-the-status-of-log-event.patch + * 0002-commands-efi-tpm-Use-grub_strcpy-instead-of-grub_mem.patch + * 0003-efi-tpm-Add-EFI_CC_MEASUREMENT_PROTOCOL-support.patch +- Measure the kernel on POWER10 and extend TPM PCRs (PED-1990) + * 0001-ibmvtpm-Add-support-for-trusted-boot-using-a-vTPM-2..patch + * 0002-ieee1275-implement-vec5-for-cas-negotiation.patch +- Fix efi pcr snapshot related funtion is defined but not used on powerpc + platform. + * safe_tpm_pcr_snapshot.patch + +------------------------------------------------------------------- +Mon Oct 24 01:58:08 UTC 2022 - Michael Chang + +- Include loopback into signed grub2 image (jsc#PED-2150) + +------------------------------------------------------------------- +Thu Oct 6 07:13:23 UTC 2022 - Michael Chang + +- Fix firmware oops after disk decrypting failure (bsc#1204037) + * 0009-Add-crypttab_entry-to-obviate-the-need-to-input-pass.patch + +------------------------------------------------------------------- +Fri Sep 23 10:13:54 UTC 2022 - Michael Chang + +- Add patch to fix kernel relocation error in low memory + * 0001-linux-fix-efi_relocate_kernel-failure.patch + +------------------------------------------------------------------- +Mon Sep 19 04:07:36 UTC 2022 - Michael Chang + +- Add safety measure to pcr snapshot by checking platform and tpm status + * safe_tpm_pcr_snapshot.patch + +------------------------------------------------------------------- +Fri Sep 16 03:56:14 UTC 2022 - Michael Chang + +- Fix installation failure due to unavailable nvram device on + ppc64le (bsc#1201361) + * 0001-grub-install-set-point-of-no-return-for-powerpc-ieee1275.patch + +------------------------------------------------------------------- +Fri Sep 16 03:12:36 UTC 2022 - Gary Ching-Pang Lin + +- Add patches to dynamically allocate additional memory regions for + EFI systems (bsc#1202438) + * 0001-mm-Allow-dynamically-requesting-additional-memory-re.patch + * 0002-kern-efi-mm-Always-request-a-fixed-number-of-pages-o.patch + * 0003-kern-efi-mm-Extract-function-to-add-memory-regions.patch + * 0004-kern-efi-mm-Pass-up-errors-from-add_memory_regions.patch + * 0005-kern-efi-mm-Implement-runtime-addition-of-pages.patch +- Enlarge the default heap size and defer the disk cache + invalidation (bsc#1202438) + * 0001-kern-efi-mm-Enlarge-the-default-heap-size.patch + * 0002-mm-Defer-the-disk-cache-invalidation.patch + +------------------------------------------------------------------- +Thu Sep 15 09:51:07 UTC 2022 - Michael Chang + +- Add patches for ALP FDE support + * 0001-devmapper-getroot-Have-devmapper-recognize-LUKS2.patch + * 0002-devmapper-getroot-Set-up-cheated-LUKS2-cryptodisk-mo.patch + * 0003-disk-cryptodisk-When-cheatmounting-use-the-sector-in.patch + * 0004-normal-menu-Don-t-show-Booting-s-msg-when-auto-booti.patch + * 0005-EFI-suppress-the-Welcome-to-GRUB-message-in-EFI-buil.patch + * 0006-EFI-console-Do-not-set-colorstate-until-the-first-te.patch + * 0007-EFI-console-Do-not-set-cursor-until-the-first-text-o.patch + * 0008-linuxefi-Use-common-grub_initrd_load.patch + * 0009-Add-crypttab_entry-to-obviate-the-need-to-input-pass.patch + * 0010-templates-import-etc-crypttab-to-grub.cfg.patch + * grub-read-pcr.patch + * efi-set-variable-with-attrs.patch + * tpm-record-pcrs.patch + * tpm-protector-dont-measure-sealed-key.patch + * tpm-protector-export-secret-key.patch + * grub-install-record-pcrs.patch + * grub-unseal-debug.patch + +------------------------------------------------------------------- +Mon Aug 29 03:48:55 UTC 2022 - Michael Chang + +- Fix out of memory error cannot be prevented via disabling tpm (bsc#1202438) + * 0001-tpm-Disable-tpm-verifier-if-tpm-is-not-present.patch + +------------------------------------------------------------------- +Thu Aug 18 02:47:28 UTC 2022 - Michael Chang + +- Fix tpm error stop tumbleweed from booting (bsc#1202374) + * 0001-tpm-Pass-unknown-error-as-non-fatal-but-debug-print-.patch +- Patch Removed + * 0001-tpm-Log-EFI_VOLUME_FULL-and-continue.patch + +------------------------------------------------------------------- +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..fe4793b 100644 --- a/grub2.spec +++ b/grub2.spec @@ -407,6 +407,65 @@ 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 +# fde +Patch901: 0001-devmapper-getroot-Have-devmapper-recognize-LUKS2.patch +Patch902: 0002-devmapper-getroot-Set-up-cheated-LUKS2-cryptodisk-mo.patch +Patch903: 0003-disk-cryptodisk-When-cheatmounting-use-the-sector-in.patch +Patch904: 0004-normal-menu-Don-t-show-Booting-s-msg-when-auto-booti.patch +Patch905: 0005-EFI-suppress-the-Welcome-to-GRUB-message-in-EFI-buil.patch +Patch906: 0006-EFI-console-Do-not-set-colorstate-until-the-first-te.patch +Patch907: 0007-EFI-console-Do-not-set-cursor-until-the-first-text-o.patch +Patch908: 0008-linuxefi-Use-common-grub_initrd_load.patch +Patch909: 0009-Add-crypttab_entry-to-obviate-the-need-to-input-pass.patch +Patch910: 0010-templates-import-etc-crypttab-to-grub.cfg.patch +Patch911: grub-read-pcr.patch +Patch912: efi-set-variable-with-attrs.patch +Patch913: tpm-record-pcrs.patch +Patch914: tpm-protector-dont-measure-sealed-key.patch +Patch915: tpm-protector-export-secret-key.patch +Patch916: grub-install-record-pcrs.patch +Patch917: grub-unseal-debug.patch +# efi mm +Patch918: 0001-tpm-Disable-tpm-verifier-if-tpm-is-not-present.patch +Patch919: 0001-mm-Allow-dynamically-requesting-additional-memory-re.patch +Patch920: 0002-kern-efi-mm-Always-request-a-fixed-number-of-pages-o.patch +Patch921: 0003-kern-efi-mm-Extract-function-to-add-memory-regions.patch +Patch922: 0004-kern-efi-mm-Pass-up-errors-from-add_memory_regions.patch +Patch923: 0005-kern-efi-mm-Implement-runtime-addition-of-pages.patch +Patch924: 0001-kern-efi-mm-Enlarge-the-default-heap-size.patch +Patch925: 0002-mm-Defer-the-disk-cache-invalidation.patch +# powerpc-ieee1275 +Patch926: 0001-grub-install-set-point-of-no-return-for-powerpc-ieee1275.patch +Patch927: safe_tpm_pcr_snapshot.patch +Patch928: 0001-linux-fix-efi_relocate_kernel-failure.patch +# (PED-996) NVMeoFC support on Grub (grub2) +Patch929: 0001-ieee1275-add-support-for-NVMeoFC.patch +Patch930: 0002-ieee1275-ofpath-enable-NVMeoF-logical-device-transla.patch +Patch931: 0003-ieee1275-change-the-logic-of-ieee1275_get_devargs.patch +Patch932: 0004-ofpath-controller-name-update.patch +# (PED-1265) TDX: Enhance grub2 measurement to TD RTMR +Patch933: 0001-commands-efi-tpm-Refine-the-status-of-log-event.patch +Patch934: 0002-commands-efi-tpm-Use-grub_strcpy-instead-of-grub_mem.patch +Patch935: 0003-efi-tpm-Add-EFI_CC_MEASUREMENT_PROTOCOL-support.patch +# (PED-1990) GRUB2: Measure the kernel on POWER10 and extend TPM PCRs +Patch936: 0001-ibmvtpm-Add-support-for-trusted-boot-using-a-vTPM-2..patch +Patch937: 0002-ieee1275-implement-vec5-for-cas-negotiation.patch Requires: gettext-runtime %if 0%{?suse_version} >= 1140 @@ -673,11 +732,11 @@ CD_MODULES="all_video boot cat configfile echo true \ font gfxmenu gfxterm gzio halt iso9660 \ jpeg minicmd normal part_apple part_msdos part_gpt \ password password_pbkdf2 png reboot search search_fs_uuid \ - search_fs_file search_label sleep test video fat loadenv" + search_fs_file search_label sleep test video fat loadenv loopback" 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 crypttab" %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 +774,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 +953,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 +975,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 @@ -1205,6 +1257,7 @@ fi %dir %{_sysconfdir}/grub.d %{_sysconfdir}/grub.d/README %config(noreplace) %{_sysconfdir}/grub.d/00_header +%config(noreplace) %{_sysconfdir}/grub.d/05_crypttab %config(noreplace) %{_sysconfdir}/grub.d/10_linux %config(noreplace) %{_sysconfdir}/grub.d/20_linux_xen %config(noreplace) %{_sysconfdir}/grub.d/30_uefi-firmware @@ -1249,6 +1302,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 diff --git a/safe_tpm_pcr_snapshot.patch b/safe_tpm_pcr_snapshot.patch new file mode 100644 index 0000000..40f729e --- /dev/null +++ b/safe_tpm_pcr_snapshot.patch @@ -0,0 +1,125 @@ +--- + grub-core/commands/tpm.c | 46 ++++++++++++++++++++++++++++++++++++---------- + util/grub-install.c | 6 ++++-- + 2 files changed, 40 insertions(+), 12 deletions(-) + +--- a/grub-core/commands/tpm.c ++++ b/grub-core/commands/tpm.c +@@ -27,8 +27,10 @@ + #include + #include + #include ++#ifdef GRUB_MACHINE_EFI + #include + #include ++#endif + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -87,12 +89,6 @@ + .verify_string = grub_tpm_verify_string, + }; + +-/* +- * Preserve current PCR values and record them to an EFI variable +- */ +-#define GRUB2_PCR_BITMASK_DEFAULT ((1 << 16) - 1) +-#define GRUB2_PCR_BITMASK_ALL ((1 << 24) - 1) +- + static const struct grub_arg_option grub_tpm_record_pcrs_options[] = + { + { +@@ -108,6 +104,14 @@ + {0, 0, 0, 0, 0, 0} + }; + ++#ifdef GRUB_MACHINE_EFI ++ ++/* ++ * Preserve current PCR values and record them to an EFI variable ++ */ ++#define GRUB2_PCR_BITMASK_DEFAULT ((1 << 16) - 1) ++#define GRUB2_PCR_BITMASK_ALL ((1 << 24) - 1) ++ + static grub_err_t + grub_tpm_parse_pcr_index (const char *word, const char **end_ret, unsigned int *index) + { +@@ -259,6 +263,10 @@ + grub_size_t size = 0; + int n, rv = 1; + ++ /* To prevent error: unable to read PCR from TPM, if no TPM device available */ ++ if (!grub_tpm_present()) ++ return GRUB_ERR_NONE; ++ + if (argc == 0) + pcr_bitmask = GRUB2_PCR_BITMASK_DEFAULT; + else +@@ -287,13 +295,28 @@ + return rv; + } + ++#else ++ ++static grub_err_t ++grub_tpm_record_pcrs (grub_extcmd_context_t ctxt __attribute__((unused)), ++ int argc __attribute__((unused)), ++ char **args __attribute__((unused))) ++{ ++ return GRUB_ERR_NONE; ++} ++ ++#endif ++ + static grub_extcmd_t cmd; + + GRUB_MOD_INIT (tpm) + { +- if (!grub_tpm_present()) +- return; ++#ifdef GRUB_MACHINE_EFI ++ if (grub_tpm_present()) ++ grub_verifier_register (&grub_tpm_verifier); ++#else + grub_verifier_register (&grub_tpm_verifier); ++#endif + + cmd = grub_register_extcmd ("tpm_record_pcrs", grub_tpm_record_pcrs, 0, + N_("LIST_OF_PCRS"), +@@ -303,8 +326,11 @@ + + GRUB_MOD_FINI (tpm) + { +- if (!grub_tpm_present()) +- return; ++#ifdef GRUB_MACHINE_EFI ++ if (grub_tpm_present()) ++ grub_verifier_unregister (&grub_tpm_verifier); ++#else + grub_verifier_unregister (&grub_tpm_verifier); ++#endif + grub_unregister_extcmd (cmd); + } +--- a/util/grub-install.c ++++ b/util/grub-install.c +@@ -1457,8 +1457,9 @@ + + grub_util_unlink (load_cfg); + +- if (1) ++ if (platform == GRUB_INSTALL_PLATFORM_X86_64_EFI && have_cryptodisk) + { ++ grub_install_push_module ("tpm"); + load_cfg_f = grub_util_fopen (load_cfg, "wb"); + have_load_cfg = 1; + fprintf (load_cfg_f, "tpm_record_pcrs 0-9\n"); +@@ -1466,7 +1467,8 @@ + + if (debug_image && debug_image[0]) + { +- load_cfg_f = grub_util_fopen (load_cfg, "wb"); ++ if (!load_cfg_f) ++ load_cfg_f = grub_util_fopen (load_cfg, "wb"); + have_load_cfg = 1; + fprintf (load_cfg_f, "set debug='%s'\n", + debug_image); diff --git a/tpm-protector-dont-measure-sealed-key.patch b/tpm-protector-dont-measure-sealed-key.patch new file mode 100644 index 0000000..8357e74 --- /dev/null +++ b/tpm-protector-dont-measure-sealed-key.patch @@ -0,0 +1,15 @@ +Index: grub-2.06/grub-core/tpm2/module.c +=================================================================== +--- grub-2.06.orig/grub-core/tpm2/module.c ++++ grub-2.06/grub-core/tpm2/module.c +@@ -139,7 +139,9 @@ grub_tpm2_protector_srk_read_keyfile (co + void *sealed_key_buffer; + grub_off_t sealed_key_read; + +- sealed_key_file = grub_file_open (filepath, GRUB_FILE_TYPE_NONE); ++ /* Using GRUB_FILE_TYPE_SIGNATURE ensures we do not hash the keyfile into PCR9 ++ * otherwise we'll never be able to predict the value of PCR9 at unseal time */ ++ sealed_key_file = grub_file_open (filepath, GRUB_FILE_TYPE_SIGNATURE); + if (!sealed_key_file) + { + grub_dprintf ("tpm2", "Could not open sealed key file.\n"); diff --git a/tpm-protector-export-secret-key.patch b/tpm-protector-export-secret-key.patch new file mode 100644 index 0000000..70eb493 --- /dev/null +++ b/tpm-protector-export-secret-key.patch @@ -0,0 +1,138 @@ +Index: grub-2.06/grub-core/tpm2/module.c +=================================================================== +--- grub-2.06.orig/grub-core/tpm2/module.c ++++ grub-2.06/grub-core/tpm2/module.c +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -46,6 +47,7 @@ struct grub_tpm2_protector_context + const char *keyfile; + TPM_HANDLE srk; + TPM_HANDLE nv; ++ const char *efivar; + }; + + static const struct grub_arg_option grub_tpm2_protector_init_cmd_options[] = +@@ -122,6 +124,16 @@ static const struct grub_arg_option grub + N_("Required in NV Index mode, the NV handle to read which must " + "readily exist on the TPM and which contains the key."), + }, ++ /* When publishing the unsealed key to a UEFI variable */ ++ { ++ .longarg = "efivar", ++ .shortarg = 'E', ++ .flags = 0, ++ .arg = NULL, ++ .type = ARG_TYPE_STRING, ++ .doc = ++ N_("Publish the unsealed key to the indicated UEFI variable."), ++ }, + /* End of list */ + {0, 0, 0, 0, 0, 0} + }; +@@ -302,6 +314,34 @@ grub_tpm2_protector_srk_get (const struc + } + + static grub_err_t ++grub_tpm2_protector_publish_key (grub_uint8_t *key, grub_size_t key_size, ++ const char *var_name) ++{ ++ grub_efi_guid_t vendor_guid = { 0x58aca851, 0x8af7, 0x4738, { 0xa5, 0x42, 0x26, 0x6e, 0x21, 0xf5, 0xca, 0xd9 }}; ++ grub_uint8_t *tmp_key; ++ grub_err_t err; ++ ++ /* It appears that EFI's set_var function overwrites the key. */ ++ tmp_key = grub_malloc (key_size); ++ if (!tmp_key) ++ { ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("No memory left to allocate temporary key buffer")); ++ return GRUB_ERR_OUT_OF_MEMORY; ++ } ++ ++ grub_memcpy(tmp_key, key, key_size); ++ ++ err = grub_efi_set_variable_with_attributes(var_name, &vendor_guid, ++ GRUB_EFI_VARIABLE_BOOTSERVICE_ACCESS | GRUB_EFI_VARIABLE_RUNTIME_ACCESS, ++ tmp_key, key_size); ++ if (err) ++ grub_error (err, N_("Failed to export LUKS key as EFI variable %s"), var_name); ++ ++ grub_free (tmp_key); ++ return err; ++} ++ ++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) + { +@@ -421,6 +461,13 @@ grub_tpm2_protector_srk_recover (const s + goto exit4; + } + ++ if (ctx->efivar) ++ { ++ rc = grub_tpm2_protector_publish_key (data.buffer, data.size, ctx->efivar); ++ if (rc) ++ goto exit4; ++ } ++ + grub_memcpy (key_out, data.buffer, data.size); + + *key = key_out; +@@ -549,20 +596,32 @@ grub_tpm2_protector_check_args (struct g + } + + static grub_err_t +-grub_tpm2_protector_parse_keyfile (const char *value, const char **keyfile) ++grub_tpm2_protector_parse_string (const char *value, const char **var, const char *arg_name) + { + if (grub_strlen (value) == 0) + return GRUB_ERR_BAD_ARGUMENT; + +- *keyfile = grub_strdup (value); +- if (!*keyfile) ++ *var = grub_strdup (value); ++ if (!*var) + return grub_error (GRUB_ERR_OUT_OF_MEMORY, +- N_("No memory to duplicate keyfile path")); ++ N_("No memory to duplicate %s argument"), arg_name); + + return GRUB_ERR_NONE; + } + + static grub_err_t ++grub_tpm2_protector_parse_keyfile (const char *value, const char **keyfile) ++{ ++ return grub_tpm2_protector_parse_string (value, keyfile, "keyfile"); ++} ++ ++static grub_err_t ++grub_tpm2_protector_parse_efivar (const char *value, const char **efivar) ++{ ++ return grub_tpm2_protector_parse_string (value, efivar, "efivar"); ++} ++ ++static grub_err_t + grub_tpm2_protector_parse_mode (const char *value, + grub_tpm2_protector_mode_t *mode) + { +@@ -650,6 +709,14 @@ grub_tpm2_protector_init_cmd_handler (gr + if (err) + return err; + } ++ ++ if (state[7].set) /* efivar */ ++ { ++ err = grub_tpm2_protector_parse_efivar (state[7].arg, ++ &grub_tpm2_protector_ctx.efivar); ++ if (err) ++ return err; ++ } + + err = grub_tpm2_protector_check_args (&grub_tpm2_protector_ctx); + diff --git a/tpm-record-pcrs.patch b/tpm-record-pcrs.patch new file mode 100644 index 0000000..4dde858 --- /dev/null +++ b/tpm-record-pcrs.patch @@ -0,0 +1,235 @@ +Index: grub-2.06/grub-core/commands/tpm.c +=================================================================== +--- grub-2.06.orig/grub-core/commands/tpm.c ++++ grub-2.06/grub-core/commands/tpm.c +@@ -26,6 +26,9 @@ + #include + #include + #include ++#include ++#include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -84,12 +87,220 @@ struct grub_file_verifier grub_tpm_verif + .verify_string = grub_tpm_verify_string, + }; + ++/* ++ * Preserve current PCR values and record them to an EFI variable ++ */ ++#define GRUB2_PCR_BITMASK_DEFAULT ((1 << 16) - 1) ++#define GRUB2_PCR_BITMASK_ALL ((1 << 24) - 1) ++ ++static const struct grub_arg_option grub_tpm_record_pcrs_options[] = ++ { ++ { ++ .longarg = "efivar", ++ .shortarg = 'E', ++ .flags = 0, ++ .arg = NULL, ++ .type = ARG_TYPE_STRING, ++ .doc = ++ N_("The EFI variable to publish the PCRs to (default GrubPcrSnapshot)"), ++ }, ++ ++ {0, 0, 0, 0, 0, 0} ++ }; ++ ++static grub_err_t ++grub_tpm_parse_pcr_index (const char *word, const char **end_ret, unsigned int *index) ++{ ++ const char *end; ++ ++ if (!grub_isdigit (word[0])) ++ return GRUB_ERR_BAD_NUMBER; ++ ++ *index = grub_strtoul(word, &end, 0); ++ if (*index > 32) ++ return GRUB_ERR_BAD_NUMBER; ++ ++ *end_ret = end; ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_tpm_parse_pcr_list (const char *arg, grub_uint32_t *bitmask) ++{ ++ const char *word, *end; ++ unsigned int index, last_index; ++ ++ if (!grub_strcmp (arg, "all")) ++ { ++ *bitmask = GRUB2_PCR_BITMASK_ALL; ++ return GRUB_ERR_NONE; ++ } ++ ++ word = arg; ++ while (1) ++ { ++ if (grub_tpm_parse_pcr_index (word, &end, &index)) ++ goto bad_pcr_index; ++ ++ if (*end == '-') ++ { ++ if (grub_tpm_parse_pcr_index (end + 1, &end, &last_index) || last_index < index) ++ goto bad_pcr_index; ++ ++ while (index <= last_index) ++ *bitmask |= (1 << (index++)); ++ } ++ else ++ *bitmask |= (1 << index); ++ ++ if (*end == '\0') ++ break; ++ ++ if (*end != ',') ++ goto bad_pcr_index; ++ ++ word = end + 1; ++ } ++ ++ return GRUB_ERR_NONE; ++ ++bad_pcr_index: ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("cannot parse PCR list \"%s\""), arg); ++} ++ ++static inline unsigned int ++nbits(grub_uint32_t mask) ++{ ++ unsigned int r = 0; ++ ++ for (; mask != 0; mask >>= 1) ++ r += (mask & 1); ++ return r; ++} ++ ++static grub_err_t ++grub_tpm_snapshot_pcrs (grub_uint32_t pcr_bitmask, const char *algo, ++ void **buffer_ret, grub_size_t *size_ret) ++{ ++ char *buffer; ++ grub_size_t size = 65536; ++ unsigned int wpos = 0; ++ grub_uint8_t pcr; ++ ++ buffer = grub_malloc (size); ++ for (pcr = 0; pcr < 32; ++pcr) ++ { ++ struct grub_tpm_digest *d; ++ unsigned int need, k; ++ ++ if (!(pcr_bitmask & (1 << pcr))) ++ continue; ++ ++ d = grub_tpm_read_pcr (pcr, algo); ++ if (d == NULL) ++ { ++ grub_error (GRUB_ERR_BAD_DEVICE, N_("unable to read PCR %d from TPM"), pcr); ++ continue; ++ } ++ ++ /* We need room for the PCR index, 2 spaces, newline, NUL. 16 should be enough. */ ++ need = 16 + grub_strlen(d->algorithm) + 2 * d->size; ++ if (wpos + need > size) ++ { ++ buffer = grub_realloc (buffer, size + need); ++ if (buffer == NULL) ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("Not enough memory when dumping PCR registers")); ++ } ++ ++ grub_snprintf (buffer + wpos, size - wpos, "%02d %s ", pcr, d->algorithm); ++ wpos = grub_strlen(buffer); ++ ++ for (k = 0; k < d->size; ++k) ++ { ++ grub_snprintf (buffer + wpos, size - wpos, "%02x", d->value[k]); ++ wpos += 2; ++ } ++ ++ buffer[wpos++] = '\n'; ++ buffer[wpos] = '\0'; ++ ++ grub_tpm_digest_free (d); ++ } ++ ++ *buffer_ret = buffer; ++ *size_ret = wpos; ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_tpm_write_pcrs_to_efi (void *data, grub_size_t size, const char *var_name) ++{ ++ grub_efi_guid_t vendor_guid = { 0x7ce323f2, 0xb841, 0x4d30, { 0xa0, 0xe9, 0x54, 0x74, 0xa7, 0x6c, 0x9a, 0x3f }}; ++ grub_err_t rc; ++ ++ rc = grub_efi_set_variable_with_attributes(var_name, &vendor_guid, ++ GRUB_EFI_VARIABLE_BOOTSERVICE_ACCESS | GRUB_EFI_VARIABLE_RUNTIME_ACCESS, ++ data, size); ++ ++ if (rc) ++ return grub_error (GRUB_ERR_BAD_DEVICE, N_("Failed to publish PCR snapshot to UEFI variable %s"), var_name); ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_tpm_record_pcrs (grub_extcmd_context_t ctxt, int argc, char **args) ++{ ++ struct grub_arg_list *state = ctxt->state; ++ grub_uint32_t pcr_bitmask = 0; ++ const char *efivar; ++ void *buffer = NULL; ++ grub_size_t size = 0; ++ int n, rv = 1; ++ ++ if (argc == 0) ++ pcr_bitmask = GRUB2_PCR_BITMASK_DEFAULT; ++ else ++ { ++ for (n = 0; n < argc; ++n) ++ if (grub_tpm_parse_pcr_list (args[n], &pcr_bitmask)) ++ return 1; ++ } ++ ++ if (grub_tpm_snapshot_pcrs (pcr_bitmask, NULL, &buffer, &size)) ++ goto out; ++ ++ if (state[0].set) ++ efivar = state[0].arg; ++ else ++ efivar = "GrubPcrSnapshot"; ++ ++ if (grub_tpm_write_pcrs_to_efi (buffer, size, efivar)) ++ goto out; ++ ++ rv = 0; ++ ++out: ++ if (buffer) ++ grub_free (buffer); ++ return rv; ++} ++ ++static grub_extcmd_t cmd; ++ + GRUB_MOD_INIT (tpm) + { + grub_verifier_register (&grub_tpm_verifier); ++ ++ cmd = grub_register_extcmd ("tpm_record_pcrs", grub_tpm_record_pcrs, 0, ++ N_("LIST_OF_PCRS"), ++ N_("Snapshot one or more PCR values and record them in an EFI variable."), ++ grub_tpm_record_pcrs_options); + } + + GRUB_MOD_FINI (tpm) + { + grub_verifier_unregister (&grub_tpm_verifier); ++ grub_unregister_extcmd (cmd); + }