GIT repo for v3: https://github.com/lcp/grub2/tree/tpm2-unlock-v3
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 ont 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 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 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 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 (1): libtasn1: Add the documentation 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 .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 | 172 +- 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 | 131 + grub-core/tpm2/buffer.c | 145 + grub-core/tpm2/module.c | 1040 +++++++ grub-core/tpm2/mu.c | 807 ++++++ grub-core/tpm2/tcg2.c | 143 + grub-core/tpm2/tpm2.c | 761 +++++ grub-core/tpm2/tpm2key.asn | 31 + grub-core/tpm2/tpm2key.c | 431 +++ 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 | 39 + 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 | 34 + include/grub/tpm2/tpm2key.h | 83 + tests/test_asn1.in | 12 + util/grub-protect.c | 1508 ++++++++++ 63 files changed, 17892 insertions(+), 31 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 v2: -: --------- > 1: f2a39b639 posix_wrap: tweaks in preparation for libtasn1 -: --------- > 2: 493f2dc86 libtasn1: import libtasn1-4.19.0 -: --------- > 3: c1c345915 libtasn1: disable code not needed in grub -: --------- > 4: 5d84feb27 libtasn1: changes for grub compatibility -: --------- > 5: 21441d802 libtasn1: compile into asn1 module -: --------- > 6: 7064cf0bc test_asn1: test module for libtasn1 -: --------- > 7: 5485acfb8 libtasn1: Add the documentation 1: 623072114 ! 8: 327bb228f protectors: Add key protectors framework @@ grub-core/kern/protectors.c (new) +grub_err_t +grub_key_protector_register (struct grub_key_protector *protector) +{ -+ if (!protector || !protector->name || !grub_strlen(protector->name)) ++ if (protector == NULL || protector->name == NULL || grub_strlen(protector->name) == 0) + return GRUB_ERR_BAD_ARGUMENT; + + if (grub_key_protectors && @@ grub-core/kern/protectors.c (new) +grub_err_t +grub_key_protector_unregister (struct grub_key_protector *protector) +{ -+ if (!protector) ++ if (protector == NULL) + return GRUB_ERR_BAD_ARGUMENT; + + grub_list_remove (GRUB_AS_LIST (protector)); @@ grub-core/kern/protectors.c (new) +{ + struct grub_key_protector *kp = NULL; + -+ if (!grub_key_protectors) ++ if (grub_key_protectors == NULL) + return GRUB_ERR_OUT_OF_RANGE; + -+ if (!protector || !grub_strlen (protector)) ++ if (protector == NULL || grub_strlen (protector) == 0) + return GRUB_ERR_BAD_ARGUMENT; + + kp = grub_named_list_find (GRUB_AS_NAMED_LIST (grub_key_protectors), + protector); -+ if (!kp) ++ if (kp == NULL) + 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 " 2: 444c0038f ! 9: ced33130b tpm2: Add TPM Software Stack (TSS) @@ include/grub/tpm2/tpm2.h (new) +#include <grub/tpm2/internal/structs.h> +#include <grub/tpm2/internal/functions.h> + -+/* 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 + 3: b579f35d3 ! 10: 2249db295 protectors: Add TPM2 Key Protector @@ Commit message 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. There are two supported key formats: + defaults. One of these arguments is the keyfile/tpm2key parameter, which + is mandatory. There are two supported key formats: 1. Raw Sealed Key (--keyfile) - The raw sealed key glues TPM2B_PUBLIC and TPM2B_PRIVATE, which are - returned from TPM2_Create, into one file, and is defined as a C - struct: - - typedef struct TPM2_SEALED_KEY { - TPM2B_PUBLIC public; - TPM2B_PRIVATE private; - } TPM2_SEALED_KEY; + When sealing a key with TPM2_Create, the public portion of the sealed + key is stored in TPM2B_PUBLIC, and the private portion is in + TPM2B_PRIVATE. The raw sealed key glues the fully marshalled + TPM2B_PUBLIC and TPM2B_PRIVATE into one file. 2. TPM 2.0 Key (--tpm2key) The following is the ASN.1 definition of TPM 2.0 Key File: + TPMPolicy ::= SEQUENCE { + CommandCode [0] EXPLICIT INTEGER + CommandPolicy [1] EXPLICIT OCTET STRING + } + + TPMAuthPolicy ::= SEQUENCE { + Name [0] EXPLICIT UTF8STRING OPTIONAL + Policy [1] EXPLICIT SEQUENCE OF TPMPolicy + } + TPMKey ::= SEQUENCE { - type OBJECT IDENTIFIER - emptyAuth [0] EXPLICIT BOOLEAN OPTIONAL - policy [1] EXPLICIT SEQUENCE OF TPMPolicy OPTIONAL - secret [2] EXPLICIT OCTET STRING OPTIONAL - authPolicy [3] EXPLICIT SEQUENCE OF TPMAuthPolicy OPTIONAL - parent INTEGER - pubkey OCTET STRING - privkey OCTET STRING - } + type OBJECT IDENTIFIER + emptyAuth [0] EXPLICIT BOOLEAN OPTIONAL + policy [1] EXPLICIT SEQUENCE OF TPMPolicy OPTIONAL + secret [2] EXPLICIT OCTET STRING OPTIONAL + authPolicy [3] EXPLICIT SEQUENCE OF TPMAuthPolicy OPTIONAL + parent INTEGER + pubkey OCTET STRING + privkey OCTET STRING + } The TPM2 key protector only expects a "sealed" key in DER encoding, so 'type' is always 2.23.133.10.1.5, 'emptyAuth' is 'TRUE', and - 'secret' is empty. TPM2B_PUBLIC is stored in 'pubkey' and - TPM2B_PRIVATE is stored in 'privkey'. 'policy' and 'authPolicy' are - ignored for the time being and will be used for the advanced features - in the future. + 'secret' is empty. 'policy' and 'authPolicy' are the possible policy + command sequences to construst the policy digest to unseal the key. + Similar to the raw sealed key, the public portion (TPM2B_PUBLIC) of + the sealed key is stored in 'pubkey', and the private portion + (TPM2B_PRIVATE) is in 'privkey'. For more details: https://www.hansenpartnership.com/draft-bottomley-tpm2-keys.html @@ Commit message - 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). + interactively or, normally, via a boot script, initialize/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, to unseal the raw sealed key file: @@ Commit message tpm2_key_protector_init --tpm2key=(hd0,gpt1)/efi/grub2/sealed-2.tpm --pcrs=7,11 cryptomount DISK2 -P tpm2 - If a user does not initialize the key protector and attempts to use it anyway, - the protector returns an error. + If a user does not initialize the key protector and attempts to use it + anyway, the protector returns an error. + + Before unsealing the key, the TPM2 key protector follows the "TPMPolicy" + sequences to enforce the TPM policy commands to construct a valid policy + digest to unseal the key. + + For the TPM 2.0 Key files, 'authPolicy' may contain multiple "TPMPolicy" + sequences, the TPM2 key protector iterates 'authPolicy' to find a valid + sequence to unseal key. If 'authPolicy' is empty or all sequences in + 'authPolicy' fail, the protector tries the one from 'policy'. In case + 'policy' is also empty, the protector creates a "TPMPolicy" sequence + based on the given PCR selection. + + For the raw sealed key, the TPM2 key protector treats the key file as a + TPM 2.0 Key file without 'authPolicy' and 'policy', so the "TPMPolicy" + sequence is always based on the PCR selection from the command + parameters. + + Currently, there is only one supported policy command: TPM2_PolicyPCR. + The command set can be extended to support advanced features, such as + as authorized policy, in the future. Signed-off-by: Hernan Gatta <hega...@linux.microsoft.com> Signed-off-by: Gary Lin <g...@suse.com> @@ grub-core/tpm2/args.c (new) + pcrs[i] = (grub_uint8_t)pcr; + *pcr_count += 1; + -+ if (!next_pcr) ++ if (next_pcr == NULL) + break; + + current_pcr = next_pcr + 1; @@ grub-core/tpm2/args.c (new) + *bank = TPM_ALG_SHA256; + else if (grub_strcasecmp (value, "SHA384") == 0) + *bank = TPM_ALG_SHA384; ++ else if (grub_strcasecmp (value, "SHA512") == 0) ++ *bank = TPM_ALG_SHA512; + else + return grub_error (GRUB_ERR_OUT_OF_RANGE, + N_("Value '%s' is not a valid PCR bank"), value); @@ grub-core/tpm2/module.c (new) +#include <grub/extcmd.h> +#include <grub/file.h> +#include <grub/libtasn1.h> ++#include <grub/list.h> +#include <grub/misc.h> +#include <grub/mm.h> +#include <grub/protector.h> +#include <grub/tpm2/buffer.h> +#include <grub/tpm2/internal/args.h> ++#include <grub/tpm2/internal/types.h> +#include <grub/tpm2/mu.h> +#include <grub/tpm2/tpm2.h> +#include <grub/tpm2/tpm2key.h> @@ grub-core/tpm2/module.c (new) + /* 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) ++ 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, @@ grub-core/tpm2/module.c (new) + } + + file_size = grub_file_size (file); -+ if (!file_size) ++ if (file_size == 0) + { + grub_dprintf ("tpm2", "Could not read file size: %s\n", filepath); + grub_file_close (file); @@ grub-core/tpm2/module.c (new) + } + + read_buffer = grub_malloc (file_size); -+ if (!read_buffer) ++ if (read_buffer == NULL) + { + grub_dprintf ("tpm2", "Could not allocate buffer for %s.\n", filepath); + grub_file_close (file); @@ grub-core/tpm2/module.c (new) +static grub_err_t +grub_tpm2_protector_srk_unmarshal_tpm2key (void *sealed_key, + grub_size_t sealed_key_size, ++ tpm2key_policy_t *policy_seq, ++ tpm2key_authpolicy_t *authpol_seq, + grub_uint32_t *parent, + TPM2_SEALED_KEY *sk) +{ @@ grub-core/tpm2/module.c (new) + struct grub_tpm2_buffer buf; + grub_err_t err; + ++ /* ++ * Start to parse the tpm2key file ++ * TPMKey ::= SEQUENCE { ++ * type OBJECT IDENTIFIER, ++ * emptyAuth [0] EXPLICIT BOOLEAN OPTIONAL, ++ * policy [1] EXPLICIT SEQUENCE OF TPMPolicy OPTIONAL, ++ * secret [2] EXPLICIT OCTET STRING OPTIONAL, ++ * authPolicy [3] EXPLICIT SEQUENCE OF TPMAuthPolicy OPTIONAL, ++ * parent INTEGER, ++ * pubkey OCTET STRING, ++ * privkey OCTET STRING ++ * } ++ */ + err = grub_tpm2key_start_parsing (&tpm2key, sealed_key, sealed_key_size); + if (err != GRUB_ERR_NONE) + return err; + ++ /* ++ * Retrieve the policy sequence from 'policy' ++ * policy_seq will be NULL when 'policy' is not available ++ */ ++ err = grub_tpm2key_get_policy_seq (tpm2key, policy_seq); ++ if (err != GRUB_ERR_NONE) ++ goto error; ++ ++ /* ++ * Retrieve the authpolicy sequence from 'authPolicy' ++ * authpol_seq will be NULL when 'authPolicy' is not available ++ */ ++ err = grub_tpm2key_get_authpolicy_seq (tpm2key, authpol_seq); ++ if (err != GRUB_ERR_NONE) ++ goto error; ++ ++ /* Retrieve the parent handle */ + err = grub_tpm2key_get_parent (tpm2key, &parent_tmp); + if (err != GRUB_ERR_NONE) + goto error; + *parent = parent_tmp; + ++ /* Retrieve the public part of the sealed key */ + err = grub_tpm2key_get_pubkey (tpm2key, &sealed_pub, &sealed_pub_size); + if (err != GRUB_ERR_NONE) + goto error; + ++ /* Retrieve the private part of the sealed key */ + err = grub_tpm2key_get_privkey (tpm2key, &sealed_priv, &sealed_priv_size); + if (err != GRUB_ERR_NONE) + goto error; + ++ /* Unmarshal the sealed key */ + grub_tpm2_buffer_init (&buf); + if (sealed_pub_size + sealed_priv_size > buf.cap) + { @@ grub-core/tpm2/module.c (new) + err = GRUB_ERR_NONE; + +error: ++ /* End the parsing */ + grub_tpm2key_end_parsing (tpm2key); + grub_free (sealed_pub); + grub_free (sealed_priv); @@ grub-core/tpm2/module.c (new) +} + +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) ++grub_tpm2_protector_policypcr (TPMI_SH_AUTH_SESSION session, ++ struct grub_tpm2_buffer *cmd_buf) +{ ++ TPM2B_DIGEST pcr_digest; ++ TPML_PCR_SELECTION pcr_sel; + TPM_RC rc; -+ TPM2_SEALED_KEY sealed_key; -+ void *file_bytes; -+ grub_size_t file_size; -+ TPM_HANDLE parent_handle = 0; -+ TPM_HANDLE srk_handle; -+ TPM2B_NONCE nonceCaller = { 0 }; -+ TPMT_SYM_DEF symmetric = { 0 }; -+ TPMI_SH_AUTH_SESSION session; -+ TPML_PCR_SELECTION pcrSel = { ++ grub_err_t err; ++ ++ grub_tpm2_mu_TPM2B_DIGEST_Unmarshal (cmd_buf, &pcr_digest); ++ grub_tpm2_mu_TPML_PCR_SELECTION_Unmarshal (cmd_buf, &pcr_sel); ++ if (cmd_buf->error) ++ { ++ err = GRUB_ERR_BAD_ARGUMENT; ++ return grub_error (err, N_("Failed to unmarshal the buffer for " ++ "TPM2_PolicyPCR")); ++ } ++ ++ rc = TPM2_PolicyPCR (session, NULL, &pcr_digest, &pcr_sel, NULL); ++ if (rc != TPM_RC_SUCCESS) ++ { ++ err = GRUB_ERR_BAD_DEVICE; ++ grub_error (err, N_("Failed to submit PCR policy (TPM2_PolicyPCR " ++ "failed with TSS/TPM error %u)"), rc); ++ return err; ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_tpm2_protector_enforce_policy (tpm2key_policy_t policy, TPMI_SH_AUTH_SESSION session) ++{ ++ struct grub_tpm2_buffer buf; ++ grub_err_t err; ++ ++ grub_tpm2_buffer_init (&buf); ++ if (policy->cmd_policy_len > buf.cap) ++ { ++ return GRUB_ERR_BAD_ARGUMENT; ++ } ++ ++ grub_memcpy (buf.data, policy->cmd_policy, policy->cmd_policy_len); ++ buf.size = policy->cmd_policy_len; ++ ++ switch (policy->cmd_code) ++ { ++ case TPM_CC_PolicyPCR: ++ err = grub_tpm2_protector_policypcr (session, &buf); ++ break; ++ default: ++ err = GRUB_ERR_BAD_ARGUMENT; ++ grub_error (err, N_("Unknown TPM Command: %x"), policy->cmd_code); ++ } ++ ++ return err; ++} ++ ++static grub_err_t ++grub_tpm2_protector_enforce_policy_seq (tpm2key_policy_t policy_seq, ++ TPMI_SH_AUTH_SESSION session) ++{ ++ tpm2key_policy_t policy; ++ grub_err_t err; ++ ++ FOR_LIST_ELEMENTS (policy, policy_seq) ++ { ++ err = grub_tpm2_protector_enforce_policy (policy, session); ++ if (err != GRUB_ERR_NONE) ++ return err; ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_tpm2_protector_simple_policy_seq (const struct grub_tpm2_protector_context *ctx, ++ tpm2key_policy_t *policy_seq) ++{ ++ tpm2key_policy_t policy = NULL; ++ struct grub_tpm2_buffer buf; ++ TPML_PCR_SELECTION pcr_sel = { + .count = 1, + .pcrSelections = { + { @@ grub-core/tpm2/module.c (new) + }, + } + }; ++ grub_uint8_t i; ++ grub_err_t err; ++ ++ if (policy_seq == NULL) ++ return GRUB_ERR_BAD_ARGUMENT; ++ ++ grub_tpm2_buffer_init (&buf); ++ ++ for (i = 0; i < ctx->pcr_count; i++) ++ TPMS_PCR_SELECTION_SelectPCR (&pcr_sel.pcrSelections[0], ctx->pcrs[i]); ++ ++ grub_tpm2_buffer_pack_u16 (&buf, 0); ++ grub_tpm2_mu_TPML_PCR_SELECTION_Marshal (&buf, &pcr_sel); ++ ++ if (buf.error) ++ return GRUB_ERR_BAD_ARGUMENT; ++ ++ policy = grub_malloc (sizeof(struct tpm2key_policy)); ++ if (policy == NULL) ++ { ++ err = GRUB_ERR_OUT_OF_MEMORY; ++ goto error; ++ } ++ policy->cmd_code = TPM_CC_PolicyPCR; ++ policy->cmd_policy = grub_malloc (buf.size); ++ if (policy->cmd_policy == NULL) ++ { ++ err = GRUB_ERR_OUT_OF_MEMORY; ++ goto error; ++ } ++ grub_memcpy (policy->cmd_policy, buf.data, buf.size); ++ policy->cmd_policy_len = buf.size; ++ ++ grub_list_push (GRUB_AS_LIST_P (policy_seq), GRUB_AS_LIST (policy)); ++ ++ return GRUB_ERR_NONE; ++ ++error: ++ grub_free (policy); ++ ++ return err; ++} ++ ++static grub_err_t ++grub_tpm2_protector_unseal (tpm2key_policy_t policy_seq, TPM_HANDLE sealed_handle, ++ grub_uint8_t **key, grub_size_t *key_size) ++{ + TPMS_AUTH_COMMAND authCmd = { 0 }; -+ TPM_HANDLE sealed_key_handle; -+ TPM2B_NAME name; + TPM2B_SENSITIVE_DATA data; ++ TPM2B_NONCE nonceCaller = { 0 }; ++ TPMT_SYM_DEF symmetric = { 0 }; ++ TPMI_SH_AUTH_SESSION session; + grub_uint8_t *key_out; -+ grub_uint8_t i; ++ TPM_RC rc; ++ grub_err_t err; ++ ++ 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, NULL, &nonceCaller, NULL, ++ TPM_SE_POLICY, &symmetric, TPM_ALG_SHA256, ++ &session, NULL, NULL); ++ if (rc != TPM_RC_SUCCESS) ++ { ++ grub_error (err, N_("Failed to start auth session (TPM2_StartAuthSession " ++ "failed with TSS/TPM error %u)"), rc); ++ goto error; ++ } ++ ++ /* Enforce the policy command sequence */ ++ err = grub_tpm2_protector_enforce_policy_seq (policy_seq, session); ++ if (err != GRUB_ERR_NONE) ++ goto error; ++ ++ /* Unseal Sealed Key */ ++ authCmd.sessionHandle = session; ++ rc = TPM2_Unseal (sealed_handle, &authCmd, &data, NULL); ++ if (rc != TPM_RC_SUCCESS) ++ { ++ grub_error (err, N_("Failed to unseal sealed key (TPM2_Unseal failed " ++ "with TSS/TPM error %u)"), rc); ++ goto error; ++ } ++ ++ /* Epilogue */ ++ 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")); ++ goto error; ++ } ++ ++ grub_memcpy (key_out, data.buffer, data.size); ++ ++ *key = key_out; ++ *key_size = data.size; ++ ++ err = GRUB_ERR_NONE; ++ ++error: ++ TPM2_FlushContext (session); ++ ++ 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) ++{ ++ TPMS_AUTH_COMMAND authCmd = { 0 }; ++ TPM2_SEALED_KEY sealed_key; ++ TPM2B_NAME name; ++ void *file_bytes; ++ grub_size_t file_size; ++ TPM_HANDLE parent_handle = 0; ++ TPM_HANDLE srk_handle; ++ TPM_HANDLE sealed_handle; ++ tpm2key_policy_t policy_seq = NULL; ++ tpm2key_authpolicy_t authpol = NULL; ++ tpm2key_authpolicy_t authpol_seq = NULL; ++ TPM_RC rc; + grub_err_t err; + -+ /* Retrieve Sealed Key */ ++ /* ++ * Retrieve sealed key, parent handle, policy sequence, and authpolicy ++ * sequence from the key file ++ */ + if (ctx->tpm2key) + { + err = grub_tpm2_protector_srk_read_file (ctx->tpm2key, &file_bytes, + &file_size); -+ if (err) ++ if (err != GRUB_ERR_NONE) + return grub_error (err, N_("Failed to read key file %s"), ctx->tpm2key); + + err = grub_tpm2_protector_srk_unmarshal_tpm2key (file_bytes, + file_size, ++ &policy_seq, ++ &authpol_seq, + &parent_handle, + &sealed_key); -+ if (err) ++ if (err != GRUB_ERR_NONE) + { + grub_error (err, N_("Failed to unmarshal key, ensure the key file is in " -+ "TPM wire format")); ++ "TPM 2.0 Key File format")); + goto exit1; + } + } @@ grub-core/tpm2/module.c (new) + { + err = grub_tpm2_protector_srk_read_file (ctx->keyfile, &file_bytes, + &file_size); -+ if (err) ++ if (err != GRUB_ERR_NONE) + return grub_error (err, N_("Failed to read key file %s"), ctx->keyfile); + + parent_handle = TPM_RH_OWNER; + err = grub_tpm2_protector_srk_unmarshal_keyfile (file_bytes, + file_size, + &sealed_key); -+ if (err) ++ if (err != GRUB_ERR_NONE) + { + grub_error (err, N_("Failed to unmarshal key, ensure the key file is in " -+ "TPM wire format")); ++ "TPM wire format")); + goto exit1; + } + } + -+ /* Get SRK */ -+ err = grub_tpm2_protector_srk_get (ctx, parent_handle, &srk_handle); -+ if (err) ++ /* ++ * Create a basic policy sequence based on the given PCR selection if the ++ * key file doesn't provide any policy or authpolicy sequence ++ */ ++ if (policy_seq == NULL) + { -+ grub_error (err, N_("Failed to retrieve the SRK")); -+ goto exit1; ++ err = grub_tpm2_protector_simple_policy_seq (ctx, &policy_seq); ++ if (err != GRUB_ERR_NONE) ++ 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, NULL, &nonceCaller, NULL, -+ TPM_SE_POLICY, &symmetric, TPM_ALG_SHA256, -+ &session, NULL, NULL); -+ if (rc) ++ /* ++ * Append the standalone policy sequence into the authpolicy sequence as ++ * the fallback ++ */ ++ authpol = grub_malloc (sizeof (struct tpm2key_authpolicy)); ++ if (authpol == NULL) + { -+ grub_error (err, N_("Failed to start auth session (TPM2_StartAuthSession " -+ "failed with TSS/TPM error %u)"), rc); -+ goto exit2; ++ /* ++ * Free policy_seq here since it's not included in authpol_seq ++ * yet, and grub_tpm2key_free_policy_seq() won't be able to ++ * free it. ++ */ ++ grub_tpm2key_free_policy_seq (policy_seq); ++ err = GRUB_ERR_OUT_OF_MEMORY; ++ goto exit1; + } ++ authpol->policy_seq = policy_seq; ++ grub_list_push (GRUB_AS_LIST_P (&authpol_seq), GRUB_AS_LIST (authpol)); + -+ /* 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) ++ /* Get the SRK to unseal the sealed key */ ++ err = grub_tpm2_protector_srk_get (ctx, parent_handle, &srk_handle); ++ if (err != GRUB_ERR_NONE) + { -+ grub_error (err, N_("Failed to submit PCR policy (TPM2_PolicyPCR failed " -+ "with TSS/TPM error %u)"), rc); -+ goto exit3; ++ grub_error (err, N_("Failed to retrieve the SRK")); ++ goto exit1; + } + -+ /* Load Sealed Key */ ++ /* Load the sealed key and associate it with the SRK */ + authCmd.sessionHandle = TPM_RS_PW; + rc = TPM2_Load (srk_handle, &authCmd, &sealed_key.private, &sealed_key.public, -+ &sealed_key_handle, &name, NULL); -+ 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; -+ rc = TPM2_Unseal (sealed_key_handle, &authCmd, &data, NULL); -+ if (rc) ++ &sealed_handle, &name, NULL); ++ if (rc != TPM_RC_SUCCESS) + { -+ grub_error (err, N_("Failed to unseal sealed key (TPM2_Unseal failed " ++ grub_error (err, N_("Failed to load sealed key (TPM2_Load failed " + "with TSS/TPM error %u)"), rc); -+ goto exit4; ++ goto exit2; + } + -+ /* Epilogue */ -+ key_out = grub_malloc (data.size); -+ if (!key_out) ++ /* Iterate the authpolicy sequence to find one that unseals the key */ ++ FOR_LIST_ELEMENTS (authpol, authpol_seq) + { -+ err = GRUB_ERR_OUT_OF_MEMORY; -+ grub_error (err, N_("No memory left to allocate unlock key buffer")); -+ goto exit4; ++ err = grub_tpm2_protector_unseal (authpol->policy_seq, sealed_handle, ++ key, key_size); ++ if (err == GRUB_ERR_NONE) ++ break; + } + -+ 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); ++ TPM2_FlushContext (sealed_handle); + +exit2: + TPM2_FlushContext (srk_handle); + +exit1: ++ grub_tpm2key_free_authpolicy_seq (authpol_seq); + grub_free (file_bytes); + return err; +} @@ grub-core/tpm2/module.c (new) +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) ++ if (key == NULL || key_size == NULL) + 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; ++ return grub_tpm2_protector_recover (&grub_tpm2_protector_ctx, key, key_size); +} + -+ +static grub_err_t +grub_tpm2_protector_check_args (struct grub_tpm2_protector_context *ctx) +{ @@ grub-core/tpm2/module.c (new) + ctx->mode = GRUB_TPM2_PROTECTOR_MODE_SRK; + + /* Checks for SRK mode */ -+ if (ctx->mode == GRUB_TPM2_PROTECTOR_MODE_SRK && !ctx->keyfile -+ && !ctx->tpm2key) ++ if (ctx->mode == GRUB_TPM2_PROTECTOR_MODE_SRK && ctx->keyfile == NULL ++ && ctx->tpm2key == NULL) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + N_("In SRK mode, a key file must be specified: " + "--tpm2key/-T or --keyfile/-k")); + ++ if (ctx->mode == GRUB_TPM2_PROTECTOR_MODE_SRK && ctx->keyfile ++ && ctx->tpm2key) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("In SRK mode, please specify a key file with " ++ "only --tpm2key/-T or --keyfile/-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) ++ if (ctx->mode == GRUB_TPM2_PROTECTOR_MODE_NV && ctx->nv == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + N_("In NV Index mode, an NV Index must be specified: " + "--nvindex or -n")); @@ grub-core/tpm2/module.c (new) + "specified")); + + /* Defaults assignment */ -+ if (!ctx->bank) ++ if (ctx->bank == TPM_ALG_ERROR) + ctx->bank = TPM_ALG_SHA256; + -+ if (!ctx->pcr_count) ++ if (ctx->pcr_count == 0) + { + ctx->pcrs[0] = 7; + ctx->pcr_count = 1; @@ grub-core/tpm2/module.c (new) + return GRUB_ERR_BAD_ARGUMENT; + + *file = grub_strdup (value); -+ if (!*file) ++ if (*file == NULL) + return grub_error (GRUB_ERR_OUT_OF_MEMORY, + N_("No memory to duplicate file path")); + @@ grub-core/tpm2/module.c (new) + +static grub_err_t +grub_tpm2_protector_init_cmd_handler (grub_extcmd_context_t ctxt, int argc, -+ char **args __attribute__ ((unused))) ++ char **args __attribute__ ((unused))) +{ + struct grub_arg_list *state = ctxt->state; + grub_err_t err; @@ grub-core/tpm2/module.c (new) + { + err = grub_tpm2_protector_parse_mode (state[OPTION_MODE].arg, + &grub_tpm2_protector_ctx.mode); -+ if (err) ++ if (err != GRUB_ERR_NONE) + return err; + } + @@ grub-core/tpm2/module.c (new) + err = grub_tpm2_protector_parse_pcrs (state[OPTION_PCRS].arg, + grub_tpm2_protector_ctx.pcrs, + &grub_tpm2_protector_ctx.pcr_count); -+ if (err) ++ if (err != GRUB_ERR_NONE) + return err; + } + @@ grub-core/tpm2/module.c (new) + { + err = grub_tpm2_protector_parse_bank (state[OPTION_BANK].arg, + &grub_tpm2_protector_ctx.bank); -+ if (err) ++ if (err != GRUB_ERR_NONE) + return err; + } + @@ grub-core/tpm2/module.c (new) + { + err = grub_tpm2_protector_parse_file (state[OPTION_TPM2KEY].arg, + &grub_tpm2_protector_ctx.tpm2key); -+ if (err) ++ if (err != GRUB_ERR_NONE) + return err; + } + @@ grub-core/tpm2/module.c (new) + { + err = grub_tpm2_protector_parse_file (state[OPTION_KEYFILE].arg, + &grub_tpm2_protector_ctx.keyfile); -+ if (err) ++ if (err != GRUB_ERR_NONE) + return err; + } + @@ grub-core/tpm2/module.c (new) + { + err = grub_tpm2_protector_parse_tpm_handle (state[OPTION_SRK].arg, + &grub_tpm2_protector_ctx.srk); -+ if (err) ++ if (err != GRUB_ERR_NONE) + return err; + } + @@ grub-core/tpm2/module.c (new) + { + err = grub_tpm2_protector_parse_asymmetric (state[OPTION_ASYMMETRIC].arg, + &grub_tpm2_protector_ctx.asymmetric); -+ if (err) ++ if (err != GRUB_ERR_NONE) + return err; + } + @@ grub-core/tpm2/module.c (new) + { + err = grub_tpm2_protector_parse_tpm_handle (state[OPTION_NVINDEX].arg, + &grub_tpm2_protector_ctx.nv); -+ if (err) ++ if (err != GRUB_ERR_NONE) + return err; + } + @@ grub-core/tpm2/tpm2key.c (new) + * along with GRUB. If not, see <http://www.gnu.org/licenses/>. + */ + ++#include <grub/libtasn1.h> ++#include <grub/list.h> +#include <grub/misc.h> +#include <grub/mm.h> -+#include <grub/libtasn1.h> ++#include <grub/tpm2/buffer.h> +#include <grub/tpm2/tpm2key.h> + +extern asn1_static_node tpm2key_asn1_tab[]; @@ grub-core/tpm2/tpm2key.c (new) +grub_tpm2key_get_privkey (asn1_node tpm2key, void **data, grub_size_t *size) +{ + return tpm2key_get_octstring (tpm2key, "privkey", data, size); ++} ++ ++/* ++ * Expected strings for CommandCode and CommandPolicy: ++ * policy.?XX.CommandCode ++ * policy.?XX.CommandPolicy ++ * authPolicy.?XX.Policy.?YY.CommandCode ++ * authPolicy.?XX.Policy.?YY.CommandPolicy ++ */ ++#define CMD_CODE_MAX (sizeof ("authPolicy.?XX.Policy.?YY.CommandCode")) ++#define CMD_POL_MAX (sizeof ("authPolicy.?XX.Policy.?YY.CommandPolicy")) ++ ++static int ++tpm2key_get_policy_seq (asn1_node tpm2key, const char *prefix, ++ tpm2key_policy_t *policy_seq) ++{ ++ tpm2key_policy_t tmp_seq = NULL; ++ tpm2key_policy_t policy = NULL; ++ int policy_n; ++ char cmd_code[CMD_CODE_MAX]; ++ char cmd_pol[CMD_POL_MAX]; ++ grub_size_t cmd_policy_len; ++ int i; ++ int ret; ++ ++ ret = asn1_number_of_elements (tpm2key, prefix, &policy_n); ++ if (ret != ASN1_SUCCESS) ++ return ret; ++ ++ /* ++ * Limit the number of policy commands to two digits (99) ++ * Although there is no upper bound for the number of policy commands, ++ * in practice, it takes one or two policy commands to unseal the key, ++ * so the 99 commands limit is more than enough. ++ */ ++ if (policy_n > 100 || policy_n < 1) ++ return ASN1_VALUE_NOT_VALID; ++ ++ /* ++ * Iterate the policy commands backwards since grub_list_push() prepends ++ * the item into the list. ++ */ ++ for (i = policy_n; i >= 1; i--) { ++ policy = grub_zalloc (sizeof (struct tpm2key_policy)); ++ if (policy == NULL) ++ { ++ ret = ASN1_MEM_ALLOC_ERROR; ++ goto error; ++ } ++ grub_snprintf (cmd_code, CMD_CODE_MAX, "%s.?%d.CommandCode", prefix, i); ++ grub_snprintf (cmd_pol, CMD_POL_MAX, "%s.?%d.CommandPolicy", prefix, i); ++ ++ /* CommandCode [0] EXPLICIT INTEGER */ ++ ret = asn1_read_uint32 (tpm2key, cmd_code, &policy->cmd_code); ++ if (ret != ASN1_SUCCESS) ++ return ret; ++ ++ /* CommandPolicy [1] EXPLICIT OCTET STRING */ ++ ret = tpm2key_get_octstring (tpm2key, cmd_pol, &policy->cmd_policy, ++ &cmd_policy_len); ++ if (ret != ASN1_SUCCESS) ++ { ++ goto error; ++ } ++ else if (cmd_policy_len > GRUB_TPM2_BUFFER_CAPACITY) ++ { ++ /* ++ * CommandPolicy is the marshalled parameters for the TPM command so ++ * it should not be larger than the maximum TPM2 buffer. ++ */ ++ ret = ASN1_VALUE_NOT_VALID; ++ goto error; ++ } ++ policy->cmd_policy_len = (grub_uint16_t)cmd_policy_len; ++ ++ /* Prepend the policy command into the sequence */ ++ grub_list_push (GRUB_AS_LIST_P (&tmp_seq), GRUB_AS_LIST (policy)); ++ } ++ ++ *policy_seq = tmp_seq; ++ ++ return ASN1_SUCCESS; ++ ++error: ++ if (policy) ++ { ++ grub_free (policy->cmd_policy); ++ grub_free (policy); ++ } ++ grub_tpm2key_free_policy_seq (tmp_seq); ++ ++ return ret; ++} ++ ++grub_err_t ++grub_tpm2key_get_policy_seq (asn1_node tpm2key, tpm2key_policy_t *policy_seq) ++{ ++ int ret; ++ ++ ret = tpm2key_get_policy_seq (tpm2key, "policy", policy_seq); ++ if (ret == ASN1_ELEMENT_NOT_FOUND) ++ { ++ /* "policy" is optional, so it may not be available */ ++ *policy_seq = NULL; ++ return GRUB_ERR_NONE; ++ } ++ else if (ret != ASN1_SUCCESS) ++ { ++ return GRUB_ERR_READ_ERROR; ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ ++void ++grub_tpm2key_free_policy_seq (tpm2key_policy_t policy_seq) ++{ ++ tpm2key_policy_t policy; ++ tpm2key_policy_t next; ++ ++ if (policy_seq == NULL) ++ return; ++ ++ FOR_LIST_ELEMENTS_SAFE (policy, next, policy_seq) ++ { ++ grub_free (policy->cmd_policy); ++ grub_free (policy); ++ } ++} ++ ++#define AUTHPOLICY_POL_MAX (sizeof ("authPolicy.?XX.Policy")) ++ ++grub_err_t ++grub_tpm2key_get_authpolicy_seq (asn1_node tpm2key, tpm2key_authpolicy_t *authpol_seq) ++{ ++ tpm2key_authpolicy_t tmp_seq = NULL; ++ tpm2key_authpolicy_t authpol = NULL; ++ int authpol_n; ++ char authpol_pol[AUTHPOLICY_POL_MAX]; ++ int i; ++ int ret; ++ grub_err_t err; ++ ++ ret = asn1_number_of_elements (tpm2key, "authPolicy", &authpol_n); ++ if (ret == ASN1_ELEMENT_NOT_FOUND) ++ { ++ /* "authPolicy" is optional, so it may not be available */ ++ *authpol_seq = NULL; ++ return GRUB_ERR_NONE; ++ } ++ else if (ret != ASN1_SUCCESS) ++ { ++ return GRUB_ERR_READ_ERROR; ++ } ++ ++ /* Limit the number of authPolicy elements to two digits (99) */ ++ if (authpol_n > 100 || authpol_n < 1) ++ return GRUB_ERR_OUT_OF_RANGE; ++ ++ /* ++ * Iterate the authPolicy elements backwards since grub_list_push() prepends ++ * the item into the list. ++ */ ++ for (i = authpol_n; i >= 1; i--) { ++ authpol = grub_zalloc (sizeof (struct tpm2key_authpolicy)); ++ if (authpol == NULL) ++ { ++ err = GRUB_ERR_OUT_OF_MEMORY; ++ goto error; ++ } ++ grub_snprintf (authpol_pol, AUTHPOLICY_POL_MAX, "authPolicy.?%d.Policy", i); ++ ++ ret = tpm2key_get_policy_seq (tpm2key, authpol_pol, &authpol->policy_seq); ++ if (ret != ASN1_SUCCESS) ++ { ++ err = GRUB_ERR_READ_ERROR; ++ goto error; ++ } ++ ++ /* Prepend the authPolicy element into the sequence */ ++ grub_list_push (GRUB_AS_LIST_P (&tmp_seq), GRUB_AS_LIST (authpol)); ++ } ++ ++ *authpol_seq = tmp_seq; ++ ++error: ++ if (authpol) ++ { ++ grub_tpm2key_free_policy_seq (authpol->policy_seq); ++ grub_free (authpol); ++ } ++ ++ grub_tpm2key_free_authpolicy_seq (tmp_seq); ++ ++ return err; ++} ++ ++void ++grub_tpm2key_free_authpolicy_seq (tpm2key_authpolicy_t authpol_seq) ++{ ++ tpm2key_authpolicy_t authpol; ++ tpm2key_authpolicy_t next; ++ ++ if (authpol_seq == NULL) ++ return; ++ ++ FOR_LIST_ELEMENTS_SAFE (authpol, next, authpol_seq) ++ { ++ grub_tpm2key_free_policy_seq (authpol->policy_seq); ++ grub_free (authpol); ++ } +} ## grub-core/tpm2/tpm2key_asn1_tab.c (new) ## @@ ++/* ++ * This file is generated by 'asn1Parser tpm2key.asn' and the '#include' ++ * headers are replaced with the ones in grub2. ++ * - 'grub/mm.h' for the definition of 'NULL' ++ * - 'grub/libtasn1.h' for the definition of 'asn1_static_node' ++ */ ++ +#include <grub/mm.h> +#include <grub/libtasn1.h> + @@ include/grub/tpm2/tpm2key.h (new) +#include <grub/types.h> +#include <grub/libtasn1.h> + ++/* ++ * TPMPolicy ::= SEQUENCE { ++ * CommandCode [0] EXPLICIT INTEGER, ++ * CommandPolicy [1] EXPLICIT OCTET STRING ++ * } ++ */ ++struct tpm2key_policy { ++ struct tpm2key_policy *next; ++ struct tpm2key_policy **prev; ++ grub_uint32_t cmd_code; ++ void *cmd_policy; ++ grub_uint16_t cmd_policy_len; ++}; ++typedef struct tpm2key_policy *tpm2key_policy_t; ++ ++/* ++ * TPMAuthPolicy ::= SEQUENCE { ++ * Name [0] EXPLICIT UTF8String OPTIONAL, ++ * Policy [1] EXPLICIT SEQUENCE OF TPMPolicy ++ * } ++ * ++ * Name is not a necessary part to unseal the key. Ignore it. ++ */ ++struct tpm2key_authpolicy { ++ struct tpm2key_authpolicy *next; ++ struct tpm2key_authpolicy **prev; ++ /* char *name; */ ++ tpm2key_policy_t policy_seq; ++}; ++typedef struct tpm2key_authpolicy *tpm2key_authpolicy_t; ++ +grub_err_t +grub_tpm2key_start_parsing (asn1_node *parsed_tpm2key, void *data, grub_size_t size); + @@ include/grub/tpm2/tpm2key.h (new) +grub_err_t +grub_tpm2key_get_privkey (asn1_node tpm2key, void **data, grub_size_t *size); + ++grub_err_t ++grub_tpm2key_get_policy_seq (asn1_node tpm2key, tpm2key_policy_t *policy_seq); ++ ++void ++grub_tpm2key_free_policy_seq (tpm2key_policy_t policy_seq); ++ ++grub_err_t ++grub_tpm2key_get_authpolicy_seq (asn1_node tpm2key, tpm2key_authpolicy_t *authpol_seq); ++ ++void ++grub_tpm2key_free_authpolicy_seq (tpm2key_authpolicy_t authpol_seq); ++ +#endif /* GRUB_TPM2_TPM2KEY_HEADER */ 4: 609f2c6e4 ! 11: 9ad473fd8 cryptodisk: Support key protectors @@ grub-core/disk/cryptodisk.c: static const struct grub_arg_option options[] = }; @@ grub-core/disk/cryptodisk.c: 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; + grub_cryptodisk_dev_t cr; + int i; struct cryptodisk_read_hook_ctx read_hook_data = {0}; int askpass = 0; @@ grub-core/disk/cryptodisk.c: grub_cryptodisk_scan_device_real (const char *name, goto error_no_close; if (!dev) continue; -+ crd = cr; + break; + } @@ grub-core/disk/cryptodisk.c: grub_cryptodisk_scan_device_real (const char *name, + if (!dev) + { + grub_error (GRUB_ERR_BAD_MODULE, -+ "no cryptodisk module can handle this device"); ++ "no cryptodisk module can handle this device"); + goto error_no_close; + } @@ grub-core/disk/cryptodisk.c: grub_cryptodisk_scan_device_real (const char *name, + 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; -+ } ++ { ++ if (cargs->key_cache[i].invalid) ++ continue; + -+ 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]); ++ 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 != GRUB_ERR_NONE) ++ { ++ if (grub_errno) ++ { ++ grub_print_error (); ++ grub_errno = GRUB_ERR_NONE; ++ } + -+ cargs->key_cache[i].invalid = 1; -+ continue; -+ } -+ } ++ 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_data = cargs->key_cache[i].key; -+ cargs->key_len = cargs->key_cache[i].key_len; ++ cargs->key_cache[i].invalid = 1; ++ continue; ++ } ++ } + -+ 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 -+ { -+ ret = grub_cryptodisk_insert (dev, name, source); -+ if (ret != GRUB_ERR_NONE) -+ goto error; -+ goto cleanup; -+ } -+ } ++ cargs->key_data = cargs->key_cache[i].key; ++ cargs->key_len = cargs->key_cache[i].key_len; - ret = grub_cryptodisk_insert (dev, name, source); - if (ret != GRUB_ERR_NONE) ++ ret = cr->recover_key (source, dev, cargs); ++ if (ret != GRUB_ERR_NONE) ++ { ++ 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 ++ { ++ ret = grub_cryptodisk_insert (dev, name, source); ++ if (ret != GRUB_ERR_NONE) ++ goto error; ++ 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); ++ 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-core/disk/cryptodisk.c: grub_cryptodisk_scan_device_real (const char *name, + 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); ++ 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; ++ 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; -+ } ++ { ++ 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); ++ ret = cr->recover_key (source, dev, cargs); + if (ret != GRUB_ERR_NONE) + goto error; + @@ grub-core/disk/cryptodisk.c: grub_cryptodisk_scan_device (const char *name, +{ + int i; + -+ if (!cargs->key_cache) ++ if (cargs->key_cache == NULL || cargs->protectors == NULL) + return; + + for (i = 0; cargs->protectors[i]; i++) @@ grub-core/disk/cryptodisk.c: grub_cmd_cryptomount (grub_extcmd_context_t ctxt, i + if (state[OPTION_PASSWORD].set && state[OPTION_PROTECTOR].set) /* password and key protector */ + return grub_error (GRUB_ERR_BAD_ARGUMENT, -+ "a password and a key protector cannot both be set"); ++ "a password and a key protector cannot both be set"); + if (state[OPTION_PASSWORD].set) /* password */ { @@ grub-core/disk/cryptodisk.c: grub_cmd_cryptomount (grub_extcmd_context_t ctxt, i + { + cargs.key_cache = grub_zalloc (state[OPTION_PROTECTOR].set * sizeof (*cargs.key_cache)); + if (!cargs.key_cache) -+ return grub_error (GRUB_ERR_OUT_OF_MEMORY, -+ "no memory for key protector key cache"); ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "no memory for key protector key cache"); + cargs.protectors = state[OPTION_PROTECTOR].args; + } + @@ grub-core/disk/cryptodisk.c: grub_cmd_cryptomount (grub_extcmd_context_t ctxt, i dev = grub_cryptodisk_get_by_uuid (args[0]); if (dev) { -+ grub_cryptodisk_clear_key_cache (&cargs); ++ grub_cryptodisk_clear_key_cache (&cargs); grub_dprintf ("cryptodisk", "already mounted as crypto%lu\n", dev->id); return GRUB_ERR_NONE; @@ grub-core/disk/cryptodisk.c: grub_cmd_cryptomount (grub_extcmd_context_t ctxt, i disk = grub_disk_open (diskname); if (!disk) { -+ grub_cryptodisk_clear_key_cache (&cargs); ++ grub_cryptodisk_clear_key_cache (&cargs); if (disklast) *disklast = ')'; return grub_errno; @@ grub-core/disk/cryptodisk.c: grub_cmd_cryptomount (grub_extcmd_context_t ctxt, i { grub_dprintf ("cryptodisk", "already mounted as crypto%lu\n", dev->id); grub_disk_close (disk); -+ grub_cryptodisk_clear_key_cache (&cargs); ++ grub_cryptodisk_clear_key_cache (&cargs); if (disklast) *disklast = ')'; return GRUB_ERR_NONE; @@ include/grub/cryptodisk.h: typedef gcry_err_code_t + 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. */ ++ /* ++ * 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; +}; + 5: 8547f130d ! 12: aa6210c44 util/grub-protect: Add new tool @@ util/grub-protect.c (new) + void *buf; + + f = fopen (filepath, "rb"); -+ if (!f) ++ if (f == NULL) + return GRUB_ERR_FILE_NOT_FOUND; + + if (fseek (f, 0, SEEK_END)) @@ util/grub-protect.c (new) + } + + len = ftell (f); -+ if (!len) ++ if (len == 0) + { + err = GRUB_ERR_FILE_READ_ERROR; + goto exit1; @@ util/grub-protect.c (new) + rewind (f); + + buf = grub_malloc (len); -+ if (!buf) ++ if (buf == NULL) + { + err = GRUB_ERR_OUT_OF_MEMORY; + goto exit1; @@ util/grub-protect.c (new) + FILE *f; + + f = fopen (filepath, "wb"); -+ if (!f) ++ if (f == NULL) + return GRUB_ERR_FILE_NOT_FOUND; + + if (fwrite (buffer, buffer_size, 1, f) != 1) @@ util/grub-protect.c (new) + int n; + + grub_path = grub_canonicalize_file_name (filepath); -+ if (!grub_path) ++ if (grub_path == NULL) + goto exit1; + + devices = grub_guess_root_devices (grub_path); -+ if (!devices || !devices[0]) ++ if (devices == NULL || devices[0] == NULL) + goto exit2; + + disk = devices[0]; @@ util/grub-protect.c (new) + grub_util_pull_device (disk); + + grub_dev = grub_util_get_grub_dev (disk); -+ if (!grub_dev) ++ if (grub_dev == NULL) + goto exit3; + + dev = grub_device_open (grub_dev); -+ if (!dev) ++ if (dev == NULL) + goto exit4; + + efi_drive = grub_util_guess_efi_drive (disk); -+ if (!efi_drive) ++ if (efi_drive == NULL) + goto exit5; + + partition = grub_partition_get_name (dev->disk->partition); -+ if (!partition) ++ if (partition == NULL) + goto exit6; + + grub_drive_len = grub_strlen (efi_drive) + grub_strlen (partition) + 3; + grub_drive = grub_malloc (grub_drive_len + 1); -+ if (!grub_drive) ++ if (grub_drive == NULL) + goto exit7; + + n = grub_snprintf (grub_drive, grub_drive_len + 1, "(%s,%s)", efi_drive, @@ util/grub-protect.c (new) +grub_err_t +grub_tcg2_get_max_output_size (grub_size_t *size) +{ -+ if (!size) ++ if (size == NULL) + return GRUB_ERR_BAD_ARGUMENT; + + *size = GRUB_TPM2_BUFFER_CAPACITY; @@ util/grub-protect.c (new) + return GRUB_ERR_NONE; + + err = close (grub_protector_tpm2_fd); -+ if (err) ++ if (err != GRUB_ERR_NONE) + { + fprintf (stderr, _("Could not close TPM device (Error: %u).\n"), errno); + return GRUB_ERR_IO; @@ util/grub-protect.c (new) + + /* 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]); ++ TPMS_PCR_SELECTION_SelectPCR (&pcr_sel.pcrSelections[0], args->tpm2_pcrs[i]); + + rc = TPM2_PCR_Read (NULL, &pcr_sel, NULL, &pcr_sel_out, &pcr_values, NULL); + if (rc != TPM_RC_SUCCESS) @@ util/grub-protect.c (new) + + pcr_concat_len = pcr_digest_len * args->tpm2_pcr_count; + pcr_concat = grub_malloc (pcr_concat_len); -+ if (!pcr_concat) ++ if (pcr_concat == NULL) + { + err = GRUB_ERR_OUT_OF_MEMORY; + fprintf (stderr, _("Failed to allocate PCR concatenation buffer.\n")); @@ util/grub-protect.c (new) +extern asn1_static_node tpm2key_asn1_tab[]; + +static grub_err_t -+grub_protect_tpm2_export_tpm2key (const char *filepath, ++grub_protect_tpm2_export_tpm2key (const struct grub_protect_args *args, + TPM2_SEALED_KEY *sealed_key) +{ + const char *sealed_key_oid = "2.23.133.10.1.5"; + asn1_node asn1_def = NULL; + asn1_node tpm2key = NULL; + grub_uint32_t parent; ++ grub_uint32_t cmd_code; ++ struct grub_tpm2_buffer pol_buf; ++ TPML_PCR_SELECTION pcr_sel = { ++ .count = 1, ++ .pcrSelections = { ++ { ++ .hash = args->tpm2_bank, ++ .sizeOfSelect = 3, ++ .pcrSelect = { 0 } ++ }, ++ } ++ }; + struct grub_tpm2_buffer pub_buf; + struct grub_tpm2_buffer priv_buf; + void *der_buf = NULL; + int der_buf_size = 0; ++ int i; + int ret; + grub_err_t err; + ++ for (i = 0; i < args->tpm2_pcr_count; i++) ++ TPMS_PCR_SELECTION_SelectPCR (&pcr_sel.pcrSelections[0], args->tpm2_pcrs[i]); ++ ++ /* ++ * Prepare the parameters for TPM_CC_PolicyPCR: ++ * empty pcrDigest and the user selected PCRs ++ */ ++ grub_tpm2_buffer_init (&pol_buf); ++ grub_tpm2_buffer_pack_u16 (&pol_buf, 0); ++ grub_tpm2_mu_TPML_PCR_SELECTION_Marshal (&pol_buf, &pcr_sel); ++ + grub_tpm2_buffer_init (&pub_buf); + grub_tpm2_mu_TPM2B_PUBLIC_Marshal (&pub_buf, &sealed_key->public); + grub_tpm2_buffer_init (&priv_buf); + grub_tpm2_mu_TPM2B_Marshal (&priv_buf, sealed_key->private.size, + sealed_key->private.buffer); -+ if (pub_buf.error || priv_buf.error) ++ if (pub_buf.error != 0 || priv_buf.error != 0) + return GRUB_ERR_BAD_ARGUMENT; + + ret = asn1_array2tree (tpm2key_asn1_tab, &asn1_def, NULL); @@ util/grub-protect.c (new) + goto error; + } + -+ /* Remove 'policy' */ -+ ret = asn1_write_value (tpm2key, "policy", NULL, 0); ++ /* Set 'policy' */ ++ ret = asn1_write_value (tpm2key, "policy", "NEW", 1); ++ if (ret != ASN1_SUCCESS) ++ { ++ err = GRUB_ERR_BAD_ARGUMENT; ++ goto error; ++ } ++ cmd_code = grub_cpu_to_be32 (TPM_CC_PolicyPCR); ++ ret = asn1_write_value (tpm2key, "policy.?LAST.CommandCode", &cmd_code, ++ sizeof (cmd_code)); ++ if (ret != ASN1_SUCCESS) ++ { ++ err = GRUB_ERR_BAD_ARGUMENT; ++ goto error; ++ } ++ ret = asn1_write_value (tpm2key, "policy.?LAST.CommandPolicy", &pol_buf.data, ++ pol_buf.size); + if (ret != ASN1_SUCCESS) + { + err = GRUB_ERR_BAD_ARGUMENT; @@ util/grub-protect.c (new) + goto error; + } + -+ err = grub_protect_write_file (filepath, der_buf, der_buf_size); -+ if (err) ++ err = grub_protect_write_file (args->tpm2_outfile, der_buf, der_buf_size); ++ if (err != GRUB_ERR_NONE) + fprintf (stderr, _("Could not write tpm2key file (Error: %u).\n"), + errno); + @@ util/grub-protect.c (new) + 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) ++ if (buf.error != 0) + return GRUB_ERR_BAD_ARGUMENT; + + err = grub_protect_write_file (filepath, buf.data, buf.size); -+ if (err) ++ if (err != GRUB_ERR_NONE) + fprintf (stderr, _("Could not write sealed key file (Error: %u).\n"), + errno); + @@ util/grub-protect.c (new) + grub_protect_get_grub_drive_for_file (args->tpm2_outfile, &grub_drive); + + err = grub_protect_tpm2_open_device (args->tpm2_device); -+ if (err) ++ if (err != GRUB_ERR_NONE) + return err; + + err = grub_protect_read_file (args->tpm2_keyfile, (void **)&key, &key_size); -+ if (err) ++ if (err != GRUB_ERR_NONE) + goto exit1; + + if (key_size > TPM_MAX_SYM_DATA) @@ util/grub-protect.c (new) + } + + err = grub_protect_tpm2_get_srk (args, &srk); -+ if (err) ++ if (err != GRUB_ERR_NONE) + goto exit2; + + err = grub_protect_tpm2_get_policy_digest (args, &policy_digest); -+ if (err) ++ if (err != GRUB_ERR_NONE) + goto exit3; + + err = grub_protect_tpm2_seal (&policy_digest, srk, key, key_size, + &sealed_key); -+ if (err) ++ if (err != GRUB_ERR_NONE) + goto exit3; + + if (args->tpm2_tpm2key) -+ err = grub_protect_tpm2_export_tpm2key (args->tpm2_outfile, &sealed_key); ++ err = grub_protect_tpm2_export_tpm2key (args, &sealed_key); + else + err = grub_protect_tpm2_export_sealed_key (args->tpm2_outfile, &sealed_key); -+ if (err) ++ if (err != GRUB_ERR_NONE) + goto exit3; + + if (grub_drive) @@ util/grub-protect.c (new) + TPMS_AUTH_COMMAND authCommand = { 0 }; + grub_err_t err; + -+ if (!args->tpm2_evict) ++ if (args->tpm2_evict == 0) + { + printf (_("--tpm2-evict not specified, nothing to do.\n")); + return GRUB_ERR_NONE; + } + + err = grub_protect_tpm2_open_device (args->tpm2_device); -+ if (err) ++ if (err != GRUB_ERR_NONE) + return err; + + /* Find SRK */ @@ util/grub-protect.c (new) + return GRUB_ERR_BAD_ARGUMENT; + } + -+ if (!args->tpm2_keyfile) ++ if (args->tpm2_keyfile == NULL) + { + fprintf (stderr, _("--tpm2-keyfile must be specified.\n")); + return GRUB_ERR_BAD_ARGUMENT; + } + -+ if (!args->tpm2_outfile) ++ if (args->tpm2_outfile == NULL) + { + fprintf (stderr, _("--tpm2-outfile must be specified.\n")); + return GRUB_ERR_BAD_ARGUMENT; + } + -+ if (!args->tpm2_device) ++ if (args->tpm2_device == NULL) + args->tpm2_device = "/dev/tpm0"; + -+ if (!args->tpm2_pcr_count) ++ if (args->tpm2_pcr_count == 0) + { + args->tpm2_pcrs[0] = 7; + args->tpm2_pcr_count = 1; + } + -+ if (!args->tpm2_srk) ++ if (args->tpm2_srk == 0) + args->tpm2_srk = TPM2_SRK_HANDLE; + -+ if (!args->tpm2_asymmetric) ++ if (args->tpm2_asymmetric == TPM_ALG_ERROR) + args->tpm2_asymmetric = TPM_ALG_RSA; + -+ if (!args->tpm2_bank) ++ if (args->tpm2_bank == TPM_ALG_ERROR) + args->tpm2_bank = TPM_ALG_SHA256; + + break; @@ util/grub-protect.c (new) + return GRUB_ERR_BAD_ARGUMENT; + } + -+ if (!args->tpm2_device) ++ if (args->tpm2_device == NULL) + args->tpm2_device = "/dev/tpm0"; + -+ if (!args->tpm2_srk) ++ if (args->tpm2_srk == 0) + args->tpm2_srk = TPM2_SRK_HANDLE; + + break; @@ util/grub-protect.c (new) + + err = grub_tpm2_protector_parse_pcrs (arg, args->tpm2_pcrs, + &args->tpm2_pcr_count); -+ if (err) ++ if (err != GRUB_ERR_NONE) + { -+ if (grub_errno) ++ if (grub_errno != GRUB_ERR_NONE) + grub_print_error (); + return EINVAL; + } @@ util/grub-protect.c (new) + } + + err = grub_tpm2_protector_parse_tpm_handle (arg, &args->tpm2_srk); -+ if (err) ++ if (err != GRUB_ERR_NONE) + { -+ if (grub_errno) ++ if (grub_errno != GRUB_ERR_NONE) + grub_print_error (); + return EINVAL; + } @@ util/grub-protect.c (new) + } + + err = grub_tpm2_protector_parse_asymmetric (arg, &args->tpm2_asymmetric); -+ if (err) ++ if (err != GRUB_ERR_NONE) + { -+ if (grub_errno) ++ if (grub_errno != GRUB_ERR_NONE) + grub_print_error (); + return EINVAL; + } @@ util/grub-protect.c (new) + } + + err = grub_tpm2_protector_parse_bank (arg, &args->tpm2_bank); -+ if (err) ++ if (err != GRUB_ERR_NONE) + { -+ if (grub_errno) ++ if (grub_errno != GRUB_ERR_NONE) + grub_print_error (); + return EINVAL; + } @@ util/grub-protect.c (new) + grub_protect_init (&argc, &argv); + + err = grub_protect_args_verify (&args); -+ if (err) ++ if (err != GRUB_ERR_NONE) + goto exit; + + err = grub_protect_dispatch (&args); -+ if (err) ++ if (err != GRUB_ERR_NONE) + goto exit; + +exit: -- 2.35.3 _______________________________________________ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel