grub-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH v3 00/12] Automatic Disk Unlock with TPM2


From: Gary Lin
Subject: [PATCH v3 00/12] Automatic Disk Unlock with TPM2
Date: Wed, 12 Apr 2023 14:15:41 +0800

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 <OKir@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 <hegatta@linux.microsoft.com>
         Signed-off-by: Gary Lin <glin@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




reply via email to

[Prev in Thread] Current Thread [Next in Thread]