GIT repo for v7: https://github.com/lcp/grub2/tree/tpm2-unlock-v7
This patch series is based on "Automatic TPM Disk Unlock"(*1) posted by Hernan Gatta to introduce the key protector framework and TPM2 stack to GRUB2, and this could be a useful feature for the systems to implement full disk encryption. To support TPM 2.0 Key File format(*2), patch 1~6 are grabbed from Daniel Axtens's "appended signature secure boot support" (*3) to import libtasn1 into grub2. Besides, the libtasn1 version is upgraded to 4.19.0 instead of 4.16.0 in the original patch. Patch 7 adds the document for libtasn1 and the steps to upgrade the library. Patch 8~12 are Hernan Gatta's patches with the follow-up fixes and improvements: - Converting 8 spaces into 1 tab - Merging the minor build fix from Michael Chang - Replacing "lu" with "PRIuGRUB_SIZE" for grub_dprintf - Adding "enable = efi" to the tpm2 module in grub-core/Makefile.core.def - Rebasing "cryptodisk: Support key protectors" to the git master - Removing the measurement on the sealed key - Based on the patch from Olaf Kirch <o...@suse.com> - Adjusting the input parameters of TPM2_EvictControl to match the order in "TCG TPM2 Part3 Commands" - Declaring the input arguments of TPM2 functions as const - Resending TPM2 commands on TPM_RC_RETRY - Adding checks for the parameters of TPM2 commands - Packing the missing authorization command for TPM2_PCR_Read - Tweaking the TPM2 command functions to allow some parameters to be NULL so that we don't have to declare empty variables - Only enabling grub-protect for "efi" since the TPM2 stack currently relies on the EFI TCG2 protocol to send TPM2 commands - Using grub_cpu_to_be*() in the TPM2 stack instead of grub_swap_bytes*() which may cause problems in big-indian machines - Changing the short name of "--protector" of "cryptomount" from "-k" to "-P" to avoid the conflict with "--key-file" - Supporting TPM 2.0 Key File Format besides the raw sealed key - Adding the external libtasn1 dependency to grub-protect to write the TPM 2.0 Key files Patch 13~16 implement the authorized policy support. Patch 17 implements the missing NV index mode. (Thanks to Patrick Colp) Patch 18 improves the 'cryptomount' command to fall back to the passphrase mode when the key protector fails to unlock the encrypted partition. (Another patch from Patrick Colp) Patch 19~20 fixes the potential security issues spotted by Fabian Vogt. To utilize the TPM2 key protector to unlock the encrypted partition (sdb1), here are the sample steps: 1. Add an extra random key for LUKS (luks-key) $ dd if=/dev/urandom of=luks-key bs=1 count=32 $ sudo cryptsetup luksAddKey /dev/sdb1 luks-key --pbkdf=pbkdf2 2. Seal the key $ sudo grub-protect --action=add \ --protector=tpm2 \ --tpm2key \ --tpm2-keyfile=luks-key \ --tpm2-outfile=/boot/efi/boot/grub2/sealed.tpm 3. Unseal the key with the proper commands in grub.cfg: tpm2_key_protector_init --tpm2key=(hd0,gpt1)/boot/grub2/sealed.tpm cryptomount -u <SDB1_UUID> -P tpm2 (*1) https://lists.gnu.org/archive/html/grub-devel/2022-02/msg00006.html (*2) https://www.hansenpartnership.com/draft-bottomley-tpm2-keys.html (*3) https://lists.gnu.org/archive/html/grub-devel/2021-06/msg00044.html v7: - Stopping reading SRK from the well-known persistent handle (TPM2_SRK_HANDLE, i.e. 0x81000001) by default since the persistent handle may be created by other OS and causes unsealing failure due to SRK mismatching - The user now has to specify the persistent handle with "--srk" explicitly. - Utilizing grub_error() to print more error messages - Unifying the format of the error messages from TPM2 commands v6: - Supporting more SRK types than RSA2048 and ECC_NIST_P256 - Documenting SHA512 as the supported PCR bank type in the tpm2 protector - Removing the redundant error message for grub_tpm2_protector_srk_get() since it may overwrite the real error message. - Updating the supported SRK types and PCR bank types in grub-protect - Removing the unused type: TPM2_ECC_CURVE v5: - https://lists.gnu.org/archive/html/grub-devel/2023-08/msg00113.html - GIT repo: https://github.com/lcp/grub2/tree/tpm2-unlock-v5 - Rebasing to the latest git HEAD and improving the commit messages - Implementing authorized poilcy support - Implementing NV index mode - Improving the 'cryptomount' command to fall back to the passphrase mode when the key protector fails to unlock the encrypted partition - Fixing the potential security issues v4: - https://lists.gnu.org/archive/html/grub-devel/2023-04/msg00104.html - GIT repo: https://github.com/lcp/grub2/tree/tpm2-unlock-v4 - Improving the error condition checks in cryptodisk.c - Moving the code to unseal with the standalone policy sequence below the code for authpolicy sequence - The standalone policy sequence was mistakenly prepended to to the authpolicy sequence with grub_list_push() while it should be appended. - Pushing the error messages from the authpolicy sequence into the grub_error stack so that we can list all errors from the sequence - Improving the error messages in the TPM2 protector - Amending the calculation of the max string lengths of 'Policy', 'CommandCode' and 'CommandPolicy' - Skipping the error path in grub_tpm2key_get_authpolicy_seq() on success to avoid freeing the authpolicy sequence v3: - https://lists.gnu.org/archive/html/grub-devel/2023-04/msg00055.html - GIT repo: https://github.com/lcp/grub2/tree/tpm2-unlock-v3 - Adding the document for libtasn1 - Improving the error condition checks ex: "if (!ptr)" ==> "if (ptr == NULL)" "if (err)" ==> "if (err != GRUB_ERR_NONE)" "if (rc)" ==> "if (rc != TPM_RC_SUCCESS)" - Supporting the "TPMPolicy" and "TPMAuthPolicy" sequence in the TPM 2.0 key File - Refactoring the key recover function to support "TPMPolicy" and "TPMAuthPolicy" sequence - Using TPMS_PCR_SELECTION_SelectPCR() to set the PCR bit mask - Also dropping TPM2_PCR_TO_SELECT() and TPM2_PCR_TO_BIT() which are not necessary anymore - Removing the redundant variable, 'crd', from grub_cryptodisk_scan_device_real() - Fixing the spaces/tabs in cryptodisk.c - Fixing the comment format in cryptodisk.h - Adding the defensive check for "cargs->protectors" in grub_cryptodisk_scan_device() - Improving 'grub-protect' for the better support of TPM 2.0 Key File - Adding more comments v2: - https://lists.gnu.org/archive/html/grub-devel/2023-03/msg00094.html - GIT repo: https://github.com/lcp/grub2/tree/tpm2-unlock-v2 v1: - https://lists.gnu.org/archive/html/grub-devel/2023-02/msg00130.html - GIT repo: https://github.com/lcp/grub2/tree/tpm2-unlock Daniel Axtens (6): posix_wrap: tweaks in preparation for libtasn1 libtasn1: import libtasn1-4.19.0 libtasn1: disable code not needed in grub libtasn1: changes for grub compatibility libtasn1: compile into asn1 module test_asn1: test module for libtasn1 Gary Lin (7): libtasn1: Add the documentation tpm2: Add TPM2 types, structures, and command constants tpm2: Add more marshal/unmarshal functions tpm2: Implement more TPM2 commands tpm2: Support authorized policy cryptodisk: wipe out the cached keys from protectors diskfilter: look up cryptodisk devices first Hernan Gatta (5): protectors: Add key protectors framework tpm2: Add TPM Software Stack (TSS) protectors: Add TPM2 Key Protector cryptodisk: Support key protectors util/grub-protect: Add new tool Patrick Colp (2): protectors: Implement NV index cryptodisk: Fallback to passphrase .gitignore | 2 + Makefile.util.def | 29 + configure.ac | 9 + docs/grub-dev.texi | 27 + grub-core/Makefile.am | 1 + grub-core/Makefile.core.def | 42 + grub-core/disk/cryptodisk.c | 183 +- grub-core/disk/diskfilter.c | 35 +- grub-core/kern/protectors.c | 75 + ...asn1-disable-code-not-needed-in-grub.patch | 311 ++ ...tasn1-changes-for-grub-compatibility.patch | 209 ++ grub-core/lib/libtasn1/COPYING | 16 + grub-core/lib/libtasn1/README.md | 98 + grub-core/lib/libtasn1/lib/coding.c | 1433 ++++++++++ grub-core/lib/libtasn1/lib/decoding.c | 2504 +++++++++++++++++ grub-core/lib/libtasn1/lib/element.c | 1110 ++++++++ grub-core/lib/libtasn1/lib/element.h | 42 + grub-core/lib/libtasn1/lib/errors.c | 103 + grub-core/lib/libtasn1/lib/gstr.c | 74 + grub-core/lib/libtasn1/lib/gstr.h | 50 + grub-core/lib/libtasn1/lib/int.h | 221 ++ grub-core/lib/libtasn1/lib/parser_aux.c | 1179 ++++++++ grub-core/lib/libtasn1/lib/parser_aux.h | 172 ++ grub-core/lib/libtasn1/lib/structure.c | 1227 ++++++++ grub-core/lib/libtasn1/lib/structure.h | 46 + .../tests/CVE-2018-1000654-1_asn1_tab.h | 32 + .../tests/CVE-2018-1000654-2_asn1_tab.h | 36 + .../libtasn1_wrap/tests/CVE-2018-1000654.c | 61 + .../lib/libtasn1_wrap/tests/Test_overflow.c | 138 + .../lib/libtasn1_wrap/tests/Test_simple.c | 207 ++ .../lib/libtasn1_wrap/tests/Test_strings.c | 150 + .../libtasn1_wrap/tests/object-id-decoding.c | 116 + .../libtasn1_wrap/tests/object-id-encoding.c | 120 + .../lib/libtasn1_wrap/tests/octet-string.c | 211 ++ .../lib/libtasn1_wrap/tests/reproducers.c | 81 + grub-core/lib/libtasn1_wrap/wrap.c | 26 + grub-core/lib/libtasn1_wrap/wrap_tests.c | 75 + grub-core/lib/libtasn1_wrap/wrap_tests.h | 38 + grub-core/lib/posix_wrap/limits.h | 1 + grub-core/lib/posix_wrap/stdlib.h | 8 + grub-core/lib/posix_wrap/sys/types.h | 1 + grub-core/tpm2/args.c | 177 ++ grub-core/tpm2/buffer.c | 145 + grub-core/tpm2/module.c | 1127 ++++++++ grub-core/tpm2/mu.c | 1069 +++++++ grub-core/tpm2/tcg2.c | 143 + grub-core/tpm2/tpm2.c | 1185 ++++++++ grub-core/tpm2/tpm2key.asn | 31 + grub-core/tpm2/tpm2key.c | 447 +++ grub-core/tpm2/tpm2key_asn1_tab.c | 41 + include/grub/cryptodisk.h | 16 + include/grub/libtasn1.h | 645 +++++ include/grub/protector.h | 48 + include/grub/tpm2/buffer.h | 65 + include/grub/tpm2/internal/args.h | 41 + include/grub/tpm2/internal/functions.h | 174 ++ include/grub/tpm2/internal/structs.h | 761 +++++ include/grub/tpm2/internal/types.h | 384 +++ include/grub/tpm2/mu.h | 367 +++ include/grub/tpm2/tcg2.h | 34 + include/grub/tpm2/tpm2.h | 34 + include/grub/tpm2/tpm2key.h | 83 + tests/test_asn1.in | 12 + util/grub-protect.c | 1492 ++++++++++ 64 files changed, 18979 insertions(+), 41 deletions(-) create mode 100644 grub-core/kern/protectors.c create mode 100644 grub-core/lib/libtasn1-patches/0001-libtasn1-disable-code-not-needed-in-grub.patch create mode 100644 grub-core/lib/libtasn1-patches/0002-libtasn1-changes-for-grub-compatibility.patch create mode 100644 grub-core/lib/libtasn1/COPYING create mode 100644 grub-core/lib/libtasn1/README.md create mode 100644 grub-core/lib/libtasn1/lib/coding.c create mode 100644 grub-core/lib/libtasn1/lib/decoding.c create mode 100644 grub-core/lib/libtasn1/lib/element.c create mode 100644 grub-core/lib/libtasn1/lib/element.h create mode 100644 grub-core/lib/libtasn1/lib/errors.c create mode 100644 grub-core/lib/libtasn1/lib/gstr.c create mode 100644 grub-core/lib/libtasn1/lib/gstr.h create mode 100644 grub-core/lib/libtasn1/lib/int.h create mode 100644 grub-core/lib/libtasn1/lib/parser_aux.c create mode 100644 grub-core/lib/libtasn1/lib/parser_aux.h create mode 100644 grub-core/lib/libtasn1/lib/structure.c create mode 100644 grub-core/lib/libtasn1/lib/structure.h create mode 100644 grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654-1_asn1_tab.h create mode 100644 grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654-2_asn1_tab.h create mode 100644 grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654.c create mode 100644 grub-core/lib/libtasn1_wrap/tests/Test_overflow.c create mode 100644 grub-core/lib/libtasn1_wrap/tests/Test_simple.c create mode 100644 grub-core/lib/libtasn1_wrap/tests/Test_strings.c create mode 100644 grub-core/lib/libtasn1_wrap/tests/object-id-decoding.c create mode 100644 grub-core/lib/libtasn1_wrap/tests/object-id-encoding.c create mode 100644 grub-core/lib/libtasn1_wrap/tests/octet-string.c create mode 100644 grub-core/lib/libtasn1_wrap/tests/reproducers.c create mode 100644 grub-core/lib/libtasn1_wrap/wrap.c create mode 100644 grub-core/lib/libtasn1_wrap/wrap_tests.c create mode 100644 grub-core/lib/libtasn1_wrap/wrap_tests.h create mode 100644 grub-core/tpm2/args.c create mode 100644 grub-core/tpm2/buffer.c create mode 100644 grub-core/tpm2/module.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 grub-core/tpm2/tpm2key.asn create mode 100644 grub-core/tpm2/tpm2key.c create mode 100644 grub-core/tpm2/tpm2key_asn1_tab.c create mode 100644 include/grub/libtasn1.h create mode 100644 include/grub/protector.h create mode 100644 include/grub/tpm2/buffer.h create mode 100644 include/grub/tpm2/internal/args.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 create mode 100644 include/grub/tpm2/tpm2key.h create mode 100644 tests/test_asn1.in create mode 100644 util/grub-protect.c Range-diff against v6: 1: ce1046fdf = 1: 0a5bf6746 posix_wrap: tweaks in preparation for libtasn1 2: 220080a05 = 2: ef1fd31fb libtasn1: import libtasn1-4.19.0 3: 864377f07 = 3: 5e935cf7a libtasn1: disable code not needed in grub 4: 3cfb8ddae = 4: 4ca0af563 libtasn1: changes for grub compatibility 5: 60ab496c6 = 5: badba7660 libtasn1: compile into asn1 module 6: faf04ebc4 = 6: 736e42762 test_asn1: test module for libtasn1 7: 47f892593 = 7: c33ccdb3c libtasn1: Add the documentation 8: 5288c347f = 8: 14416084f protectors: Add key protectors framework 9: c5a42cf33 = 9: 6cea227ca tpm2: Add TPM Software Stack (TSS) 10: b2c850be3 ! 10: 2a63876ca protectors: Add TPM2 Key Protector @@ grub-core/tpm2/module.c (new) + .arg = NULL, + .type = ARG_TYPE_STRING, + .doc = -+ N_("In SRK mode, the SRK handle if the SRK is persistent " -+ "(default is 0x81000001)."), ++ N_("In SRK mode, the SRK handle if the SRK is persistent."), + }, + { + .longarg = "asymmetric", @@ grub-core/tpm2/module.c (new) + grub_off_t file_size; + void *read_buffer; + grub_off_t read_n; ++ grub_err_t err; + + /* 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 */ + file = grub_file_open (filepath, GRUB_FILE_TYPE_SIGNATURE); + if (file == NULL) + { -+ grub_dprintf ("tpm2", "Could not open file: %s\n", filepath); -+ /* 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; ++ /* Push errno from grub_file_open() into the error message stack */ ++ grub_error_push(); ++ err = grub_error (GRUB_ERR_FILE_NOT_FOUND, ++ N_("Could not open file: %s\n"), ++ filepath); ++ goto error; + } + + file_size = grub_file_size (file); + if (file_size == 0) + { -+ grub_dprintf ("tpm2", "Could not read file size: %s\n", filepath); -+ grub_file_close (file); -+ return GRUB_ERR_OUT_OF_RANGE; ++ err = grub_error (GRUB_ERR_OUT_OF_RANGE, ++ N_("Could not read file size: %s"), ++ filepath); ++ goto error; + } + + read_buffer = grub_malloc (file_size); + if (read_buffer == NULL) + { -+ grub_dprintf ("tpm2", "Could not allocate buffer for %s.\n", filepath); -+ grub_file_close (file); -+ return GRUB_ERR_OUT_OF_MEMORY; ++ err = grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ N_("Could not allocate buffer for %s"), ++ filepath); ++ goto error; + } + + read_n = grub_file_read (file, read_buffer, file_size); + if (read_n != file_size) + { -+ grub_dprintf ("tpm2", "Could not retrieve file contents: %s\n", filepath); + grub_free (read_buffer); -+ grub_file_close (file); -+ return GRUB_ERR_FILE_READ_ERROR; ++ err = grub_error (GRUB_ERR_FILE_READ_ERROR, ++ N_("Could not retrieve file contents: %s"), ++ filepath); ++ goto error; + } + -+ grub_file_close (file); -+ + *buffer = read_buffer; + *buffer_size = file_size; + -+ return GRUB_ERR_NONE; ++ err = GRUB_ERR_NONE; ++ ++error: ++ grub_file_close (file); ++ ++ return err; +} + +static grub_err_t @@ grub-core/tpm2/module.c (new) + + grub_tpm2_buffer_init (&buf); + if (sealed_key_size > buf.cap) -+ { -+ grub_dprintf ("tpm2", "Sealed key file is larger than decode buffer " -+ "(%" PRIuGRUB_SIZE " vs %" PRIuGRUB_SIZE " bytes).\n", -+ sealed_key_size, buf.cap); -+ return GRUB_ERR_BAD_ARGUMENT; -+ } ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("Sealed key larger than %" PRIuGRUB_SIZE " bytes"), ++ buf.cap); + + grub_memcpy (buf.data, sealed_key, sealed_key_size); + buf.size = sealed_key_size; @@ grub-core/tpm2/module.c (new) + 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_error (GRUB_ERR_BAD_ARGUMENT, N_("Malformed TPM wire key file")); + + return GRUB_ERR_NONE; +} @@ grub-core/tpm2/module.c (new) + grub_tpm2_buffer_init (&buf); + if (sealed_pub_size + sealed_priv_size > buf.cap) + { -+ grub_dprintf ("tpm2", "Sealed key is larger than decode buffer " -+ "(%" PRIuGRUB_SIZE " vs %" PRIuGRUB_SIZE " bytes).\n", -+ sealed_pub_size, buf.cap); -+ err = GRUB_ERR_BAD_ARGUMENT; ++ err = grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("Sealed key larger than %" PRIuGRUB_SIZE " bytes"), ++ buf.cap); + goto error; + } + @@ grub-core/tpm2/module.c (new) + + if (buf.error) + { -+ grub_dprintf ("tpm2", "Could not unmarshal sealed key, it is likely " -+ "malformed.\n"); -+ err = GRUB_ERR_BAD_ARGUMENT; ++ err = grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Malformed TPM 2.0 key file")); + goto error; + } + @@ grub-core/tpm2/module.c (new) + TPM2B_NAME srkName = { 0 }; + TPM_HANDLE srkHandle; + -+ /* Find SRK */ -+ rc = TPM2_ReadPublic (ctx->srk, NULL, &public); -+ if (rc == TPM_RC_SUCCESS) ++ if (ctx->srk != 0) + { -+ *srk = ctx->srk; -+ return GRUB_ERR_NONE; -+ } ++ /* 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; ++ return grub_error (GRUB_ERR_BAD_DEVICE, ++ N_("Failed to retrieve SRK (TPM2_ReadPublic: 0x%x)"), ++ rc); + } + + /* Create SRK */ @@ grub-core/tpm2/module.c (new) + inPublic.publicArea.parameters.eccDetail.kdf.scheme = TPM_ALG_NULL; + } + else -+ return GRUB_ERR_BAD_ARGUMENT; ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Unknown SRK algorithm")); + + rc = TPM2_CreatePrimary (parent, &authCommand, &inSensitive, &inPublic, + &outsideInfo, &creationPcr, &srkHandle, &outPublic, @@ grub-core/tpm2/module.c (new) + &session, NULL, NULL); + if (rc != TPM_RC_SUCCESS) + return grub_error (GRUB_ERR_BAD_DEVICE, -+ N_("Failed to start auth session (TPM2_StartAuthSession: " -+ "0x%x)"), rc); ++ N_("Failed to start auth session (TPM2_StartAuthSession: 0x%x)"), ++ rc); + + /* Enforce the policy command sequence */ + err = grub_tpm2_protector_enforce_policy_seq (policy_seq, session); @@ grub-core/tpm2/module.c (new) + rc = TPM2_Unseal (sealed_handle, &authCmd, &data, NULL); + if (rc != TPM_RC_SUCCESS) + { -+ err = GRUB_ERR_BAD_DEVICE; -+ grub_error (err, N_("Failed to unseal sealed key (TPM2_Unseal: 0x%x)"), -+ rc); ++ err = grub_error (GRUB_ERR_BAD_DEVICE, ++ N_("Failed to unseal sealed key (TPM2_Unseal: 0x%x)"), ++ rc); + goto error; + } + @@ grub-core/tpm2/module.c (new) + key_out = grub_malloc (data.size); + if (key_out == NULL) + { -+ err = GRUB_ERR_OUT_OF_MEMORY; -+ grub_error (err, N_("No memory left to allocate unlock key buffer")); ++ err = grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ N_("No memory left to allocate unlock key buffer")); + goto error; + } + @@ grub-core/tpm2/module.c (new) + err = grub_tpm2_protector_srk_read_file (ctx->tpm2key, &file_bytes, + &file_size); + if (err != GRUB_ERR_NONE) -+ return grub_error (err, N_("Failed to read key file %s"), ctx->tpm2key); ++ return err; + + err = grub_tpm2_protector_srk_unmarshal_tpm2key (file_bytes, + file_size, @@ grub-core/tpm2/module.c (new) + &parent_handle, + &sealed_key); + if (err != GRUB_ERR_NONE) -+ { -+ grub_error (err, N_("Failed to unmarshal key, ensure the key file is in " -+ "TPM 2.0 Key File format")); -+ goto exit1; -+ } ++ goto exit1; + } + else + { + err = grub_tpm2_protector_srk_read_file (ctx->keyfile, &file_bytes, + &file_size); + if (err != GRUB_ERR_NONE) -+ return grub_error (err, N_("Failed to read key file %s"), ctx->keyfile); ++ return err; + + parent_handle = TPM_RH_OWNER; + err = grub_tpm2_protector_srk_unmarshal_keyfile (file_bytes, + file_size, + &sealed_key); + if (err != GRUB_ERR_NONE) -+ { -+ grub_error (err, N_("Failed to unmarshal key, ensure the key file is in " -+ "TPM wire format")); -+ goto exit1; -+ } ++ goto exit1; + } + + /* Get the SRK to unseal the sealed key */ @@ grub-core/tpm2/module.c (new) + &sealed_handle, &name, NULL); + if (rc != TPM_RC_SUCCESS) + { -+ err = GRUB_ERR_BAD_DEVICE; -+ grub_error (err, N_("Failed to load sealed key (TPM2_Load: 0x%x)"), rc); ++ err = grub_error (GRUB_ERR_BAD_DEVICE, ++ N_("Failed to load sealed key (TPM2_Load: 0x%x)"), ++ rc); + goto exit2; + } + ++ /* ++ * Set err to an error code to trigger the standalone policy sequence ++ * if there is no authpolicy sequence ++ */ + err = GRUB_ERR_READ_ERROR; + + /* Iterate the authpolicy sequence to find one that unseals the key */ @@ grub-core/tpm2/module.c (new) + + if (ctx->mode == GRUB_TPM2_PROTECTOR_MODE_SRK) + { -+ if (!ctx->srk) -+ ctx->srk = TPM2_SRK_HANDLE; -+ + if (!ctx->asymmetric) + { + ctx->asymmetric = TPM_ALG_RSA; @@ grub-core/tpm2/tpm2key.c (new) + */ + ret = asn1_array2tree (tpm2key_asn1_tab, &tpm2key_asn1, NULL); + if (ret != ASN1_SUCCESS) -+ return GRUB_ERR_BAD_ARGUMENT; ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("Failed to parse TPM2KEY ASN.1 array")); + + ret = asn1_create_element (tpm2key_asn1, "TPM2KEY.TPMKey", &tpm2key); + if (ret != ASN1_SUCCESS) -+ return GRUB_ERR_BAD_ARGUMENT; ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("Failed to create TPM2KEY.TPMKey")); + + ret = asn1_der_decoding (&tpm2key, data, size, NULL); + if (ret != ASN1_SUCCESS) -+ return GRUB_ERR_BAD_ARGUMENT; ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("Failed to decode TPM2KEY DER")); + + /* Check if 'type' is Sealed Key or not */ + ret = asn1_allocate_and_read (tpm2key, "type", &type_oid, &type_oid_size); + if (ret != ASN1_SUCCESS) -+ return GRUB_ERR_BAD_FILE_TYPE; ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ N_("Not a valid TPM2KEY file")); + + if (grub_memcmp (sealed_key_oid, type_oid, type_oid_size) != 0) + { -+ err = GRUB_ERR_BAD_FILE_TYPE; ++ err = grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ N_("Not a valid TPM2KEY file")); + goto error; + } + @@ grub-core/tpm2/tpm2key.c (new) + ret = asn1_allocate_and_read (tpm2key, "emptyAuth", &empty_auth, &empty_auth_size); + if (ret != ASN1_SUCCESS || grub_strncmp ("TRUE", empty_auth, empty_auth_size) != 0) + { -+ err = GRUB_ERR_BAD_ARGUMENT; ++ err = grub_error (GRUB_ERR_BAD_ARGUMENT, N_("emptyAuth not TRUE")); + goto error; + } + @@ grub-core/tpm2/tpm2key.c (new) + ret = asn1_read_value (tpm2key, "secret", NULL, &tmp_size); + if (ret != ASN1_ELEMENT_NOT_FOUND) + { -+ err = GRUB_ERR_BAD_ARGUMENT; ++ err = grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("\"secret\" not allowed for Sealed Key")); + goto error; + } + @@ grub-core/tpm2/tpm2key.c (new) + int ret; + + if (parent == NULL) -+ return GRUB_ERR_BAD_ARGUMENT; ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("NULL pointer detected")); + + if (tpm2key == NULL) -+ return GRUB_ERR_READ_ERROR; ++ return grub_error (GRUB_ERR_READ_ERROR, N_("Invalid parent node")); + + ret = asn1_read_uint32 (tpm2key, "parent", parent); + if (ret != ASN1_SUCCESS) -+ return GRUB_ERR_READ_ERROR; ++ return grub_error (GRUB_ERR_READ_ERROR, N_("Failed to retrieve parent")); + + return GRUB_ERR_NONE; +} @@ grub-core/tpm2/tpm2key.c (new) + int ret; + + if (name == NULL || data == NULL || size == NULL) -+ return GRUB_ERR_BAD_ARGUMENT; ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Invalid parameter(s)")); + + if (tpm2key == NULL) -+ return GRUB_ERR_READ_ERROR; ++ return grub_error (GRUB_ERR_READ_ERROR, N_("Invalid %s node"), name); + + ret = asn1_allocate_and_read (tpm2key, name, data, size); + if (ret != ASN1_SUCCESS) -+ return GRUB_ERR_READ_ERROR; ++ return grub_error (GRUB_ERR_READ_ERROR, ++ N_("Failed to retrieve %s"), ++ name); + + return GRUB_ERR_NONE; +} @@ grub-core/tpm2/tpm2key.c (new) + return GRUB_ERR_NONE; + } + else if (ret != ASN1_SUCCESS) -+ { -+ return GRUB_ERR_READ_ERROR; -+ } ++ return grub_error (GRUB_ERR_READ_ERROR, N_("Failed to retrieve policy")); + + return GRUB_ERR_NONE; +} @@ grub-core/tpm2/tpm2key.c (new) + return GRUB_ERR_NONE; + } + else if (ret != ASN1_SUCCESS) -+ { -+ return GRUB_ERR_READ_ERROR; -+ } ++ return grub_error (GRUB_ERR_READ_ERROR, N_("Failed to retrieve authPolicy")); + + /* Limit the number of authPolicy elements to two digits (99) */ + if (authpol_n > 100 || authpol_n < 1) -+ return GRUB_ERR_OUT_OF_RANGE; ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, ++ N_("Invalid number of autoPolicy elements")); + + /* + * Iterate the authPolicy elements backwards since grub_list_push() prepends @@ grub-core/tpm2/tpm2key.c (new) + authpol = grub_zalloc (sizeof (struct tpm2key_authpolicy)); + if (authpol == NULL) + { -+ err = GRUB_ERR_OUT_OF_MEMORY; ++ err = grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ N_("Failed to allocate memory for authPolicy")); + goto error; + } + grub_snprintf (authpol_pol, AUTHPOLICY_POL_MAX, "authPolicy.?%d.Policy", i); @@ grub-core/tpm2/tpm2key.c (new) + ret = tpm2key_get_policy_seq (tpm2key, authpol_pol, &authpol->policy_seq); + if (ret != ASN1_SUCCESS) + { -+ err = GRUB_ERR_READ_ERROR; ++ err = grub_error (GRUB_ERR_READ_ERROR, ++ N_("Failed to retrieve policy from authPolicy")); + goto error; + } + 11: 2b7018865 = 11: 180d766e4 cryptodisk: Support key protectors 12: e5a1c5fe6 ! 12: 1116bc4b9 util/grub-protect: Add new tool @@ util/grub-protect.c (new) + 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_TPM2_TPM2KEY +} grub_protect_opt; @@ util/grub-protect.c (new) + 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_TPM2_TPM2KEY = 1 << 11 ++ GRUB_PROTECT_ARG_TPM2_EVICT = 1 << 9, ++ GRUB_PROTECT_ARG_TPM2_TPM2KEY = 1 << 10 +} grub_protect_arg_t; + +typedef enum grub_protect_protector @@ util/grub-protect.c (new) + TPM_HANDLE tpm2_srk; + const char *tpm2_keyfile; + const char *tpm2_outfile; -+ int tpm2_persist; + int tpm2_evict; + int tpm2_tpm2key; +}; @@ util/grub-protect.c (new) + .arg = "NUM", + .flags = 0, + .doc = -+ N_("The SRK handle if the SRK is to be made persistent " -+ "(default is 0x81000001)."), ++ N_("The SRK handle if the SRK is to be made persistent."), + .group = 0 + }, + { @@ util/grub-protect.c (new) + .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, @@ util/grub-protect.c (new) + 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); ++ fprintf (stderr, _("Failed to read PCRs (TPM2_PCR_Read: 0x%x).\n"), rc); + return GRUB_ERR_BAD_DEVICE; + } + @@ util/grub-protect.c (new) + if (rc != TPM_RC_SUCCESS) + { + fprintf (stderr, -+ _("Failed to start trial policy session (TPM error: 0x%x).\n"), ++ _("Failed to start trial policy session (TPM2_StartAuthSession: 0x%x).\n"), + rc); + err = GRUB_ERR_BAD_DEVICE; + goto exit2; @@ util/grub-protect.c (new) + 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"), ++ fprintf (stderr, _("Failed to submit PCR policy (TPM2_PolicyPCR: 0x%x).\n"), + rc); + err = GRUB_ERR_BAD_DEVICE; + goto exit3; @@ util/grub-protect.c (new) + 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"), ++ fprintf (stderr, _("Failed to get policy digest (TPM2_PolicyGetDigest: 0x%x).\n"), + rc); + err = GRUB_ERR_BAD_DEVICE; + goto exit3; @@ util/grub-protect.c (new) + 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_srk != 0) + { -+ 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; -+ } ++ /* Find SRK */ ++ rc = TPM2_ReadPublic (args->tpm2_srk, NULL, &public); ++ if (rc == TPM_RC_SUCCESS) ++ { ++ printf (_("Read SRK from 0x%x\n"), args->tpm2_srk); ++ *srk = args->tpm2_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) -+ { -+ 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; ++ /* The handle exists but its public area could not be read. */ ++ if ((rc & ~TPM_RC_N_MASK) != TPM_RC_HANDLE) ++ { ++ fprintf (stderr, ++ _("Failed to retrieve SRK from 0x%x (TPM2_ReadPublic: 0x%x).\n"), ++ args->tpm2_srk, rc); ++ return GRUB_ERR_BAD_DEVICE; ++ } + } + + /* Create SRK */ @@ util/grub-protect.c (new) + &srkName, NULL); + if (rc != TPM_RC_SUCCESS) + { -+ fprintf (stderr, _("Failed to create SRK (TPM error: 0x%x).\n"), rc); ++ fprintf (stderr, _("Failed to create SRK (TPM2_CreatePrimary: 0x%x).\n"), rc); + return GRUB_ERR_BAD_DEVICE; + } + + /* Persist SRK */ -+ if (args->tpm2_persist) ++ if (args->tpm2_srk != 0) + { + rc = TPM2_EvictControl (TPM_RH_OWNER, srkHandle, &authCommand, + args->tpm2_srk, NULL); @@ util/grub-protect.c (new) + } + else + fprintf (stderr, -+ _("Warning: Failed to persist SRK (TPM error: 0x%x\n). " -+ "Continuing anyway...\n"), rc); ++ _("Warning: Failed to persist SRK (0x%x) (TPM2_EvictControl: 0x%x\n). " ++ "Continuing anyway...\n"), args->tpm2_srk, rc); + } + + /* Epilogue */ @@ util/grub-protect.c (new) + &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); ++ fprintf (stderr, _("Failed to seal key (TPM2_Create: 0x%x).\n"), rc); + return GRUB_ERR_BAD_DEVICE; + } + @@ util/grub-protect.c (new) + if (rc != TPM_RC_SUCCESS) + { + fprintf (stderr, -+ _("Failed to evict SRK with handle 0x%x (TPM Error: 0x%x).\n"), ++ _("Failed to evict SRK with handle 0x%x (TPM2_EvictControl: 0x%x).\n"), + args->tpm2_srk, rc); + err = GRUB_ERR_BAD_DEVICE; + goto exit2; @@ util/grub-protect.c (new) + args->tpm2_pcr_count = 1; + } + -+ if (args->tpm2_srk == 0) -+ args->tpm2_srk = TPM2_SRK_HANDLE; -+ + if (args->tpm2_asymmetric == TPM_ALG_ERROR) + { + args->tpm2_asymmetric = TPM_ALG_RSA; @@ util/grub-protect.c (new) + return GRUB_ERR_BAD_ARGUMENT; + } + -+ if (args->args & GRUB_PROTECT_ARG_TPM2_PERSIST) ++ if (args->tpm2_srk == 0) + { + fprintf (stderr, -+ _("--tpm2-persist is invalid when --action is 'remove'.\n")); ++ _("--tpm2-srk is not specified when --action is 'remove'.\n")); + return GRUB_ERR_BAD_ARGUMENT; + } + + if (args->tpm2_device == NULL) + args->tpm2_device = "/dev/tpm0"; + -+ if (args->tpm2_srk == 0) -+ args->tpm2_srk = TPM2_SRK_HANDLE; -+ + break; + + default: @@ util/grub-protect.c (new) + 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) + { 13: 9e8be3913 = 13: ec30bb3e5 tpm2: Add TPM2 types, structures, and command constants 14: edd137be2 = 14: 00aadc9db tpm2: Add more marshal/unmarshal functions 15: 7b2f93b23 = 15: 4f7c385a8 tpm2: Implement more TPM2 commands 16: effc0933b ! 16: 542c4fc6e tpm2: Support authorized policy @@ grub-core/tpm2/module.c: grub_tpm2_protector_policypcr (TPMI_SH_AUTH_SESSION ses + grub_tpm2_mu_TPM2B_DIGEST_Unmarshal (cmd_buf, &policy_ref); + grub_tpm2_mu_TPMT_SIGNATURE_Unmarshal (cmd_buf, &signature); + if (cmd_buf->error != 0) -+ { -+ err = GRUB_ERR_BAD_ARGUMENT; -+ return grub_error (err, N_("Failed to unmarshal the buffer for " -+ "TPM2_PolicyAuthorize")); -+ } ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("Failed to unmarshal the buffer for TPM2_PolicyAuthorize")); + + /* Retrieve Policy Digest */ + rc = TPM2_PolicyGetDigest (session, NULL, &pcr_policy, NULL); + if (rc != TPM_RC_SUCCESS) -+ { -+ err = GRUB_ERR_BAD_DEVICE; -+ grub_error (err, N_("Failed to get policy digest (TPM error: 0x%x)."), -+ rc); -+ return err; -+ } ++ return grub_error (GRUB_ERR_BAD_DEVICE, ++ N_("Failed to get policy digest (TPM2_PolicyGetDigest: 0x%x)."), ++ rc); + + /* Calculate the digest of the polcy for VerifySignature */ + sig_hash = TPMT_SIGNATURE_get_hash_alg (&signature); + if (sig_hash == TPM_ALG_NULL) -+ { -+ err = GRUB_ERR_BAD_ARGUMENT; -+ grub_error (err, N_("Failed to get the hash algorithm of the signature")); -+ return err; -+ } ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("Failed to get the hash algorithm of the signature")); ++ + rc = TPM2_Hash (NULL, (TPM2B_MAX_BUFFER *)&pcr_policy, sig_hash, + TPM_RH_NULL, &pcr_policy_hash, NULL, NULL); + if (rc != TPM_RC_SUCCESS) -+ { -+ err = GRUB_ERR_BAD_DEVICE; -+ grub_error (err, N_("Failed to create PCR policy hash (TPM2_Hash failed " -+ "with TSS/TPM error %u)"), rc); -+ return err; -+ } ++ return grub_error (GRUB_ERR_BAD_DEVICE, ++ N_("Failed to create PCR policy hash (TPM2_Hash: 0x%x)"), ++ rc); + + /* Load the public key */ + rc = TPM2_LoadExternal (NULL, NULL, &pubkey, TPM_RH_OWNER, + &pubkey_handle, &pubname, NULL); + if (rc != TPM_RC_SUCCESS) -+ { -+ err = GRUB_ERR_BAD_DEVICE; -+ grub_error (err, N_("Failed to load public key (TPM2_LoadExternal failed " -+ "with TSS/TPM error %u)"), rc); -+ return err; -+ } ++ return grub_error (GRUB_ERR_BAD_DEVICE, ++ N_("Failed to load public key (TPM2_LoadExternal: 0x%x)"), ++ rc); + + /* Verify the signature against the public key and the policy digest */ + rc = TPM2_VerifySignature (pubkey_handle, NULL, &pcr_policy_hash, &signature, + &verification_ticket, NULL); + if (rc != TPM_RC_SUCCESS) + { -+ err = GRUB_ERR_BAD_DEVICE; -+ grub_error (err, N_("Failed to verify signature (TPM2_VerifySignature " -+ "failed with TSS/TPM error %u)"), rc); ++ err = grub_error (GRUB_ERR_BAD_DEVICE, ++ N_("Failed to verify signature (TPM2_VerifySignature: 0x%x)"), ++ rc); + goto error; + } + @@ grub-core/tpm2/module.c: grub_tpm2_protector_policypcr (TPMI_SH_AUTH_SESSION ses + &verification_ticket, NULL); + if (rc != TPM_RC_SUCCESS) + { -+ err = GRUB_ERR_BAD_DEVICE; -+ grub_error (err, N_("Failed to authorize PCR policy (TPM2_PolicyAuthorize " -+ "failed with TSS/TPM error: 0x%u).\n"), rc); ++ err = grub_error (GRUB_ERR_BAD_DEVICE, ++ N_("Failed to authorize PCR policy (TPM2_PolicyAuthorize: 0x%x)"), ++ rc); + goto error; + } + 17: 94dd8146c = 17: 18ede7507 protectors: Implement NV index 18: 5700a35fb = 18: 6f89e2dbf cryptodisk: Fallback to passphrase 19: 0aed42f83 = 19: e17a0baf5 cryptodisk: wipe out the cached keys from protectors 20: b7157d893 = 20: 1c4f7bcd9 diskfilter: look up cryptodisk devices first -- 2.35.3 _______________________________________________ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel