grub-devel
[Top][All Lists]
Advanced

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

[PATCH v2 09/11] protectors: Add TPM2 Key Protector


From: Gary Lin
Subject: [PATCH v2 09/11] protectors: Add TPM2 Key Protector
Date: Wed, 22 Mar 2023 16:10:14 +0800

From: Hernan Gatta <hegatta@linux.microsoft.com>

The TPM2 key protector is a module that enables the automatic retrieval
of a fully-encrypted disk's unlocking key from a TPM 2.0.

The theory of operation is such that the module accepts various
arguments, most of which are optional and therefore possess reasonable
defaults. One of these arguments is the keyfile parameter, which is
mandatory. 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;

2. TPM 2.0 Key (--tpm2key)
   The following is the ASN.1 definition of TPM 2.0 Key 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
  }

  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.

  For more details: 
https://www.hansenpartnership.com/draft-bottomley-tpm2-keys.html

This sealed key file is created via the grub-protect tool. The tool
utilizes the TPM's sealing functionality to seal (i.e., encrypt) an
unlocking key using a Storage Root Key (SRK) to the values of various
Platform Configuration Registers (PCRs). These PCRs reflect the state
of the system as it boots. If the values are as expected, the system
may be considered trustworthy, at which point the TPM allows for a
caller to utilize the private component of the SRK to unseal (i.e.,
decrypt) the sealed key file. The caller, in this case, is this key
protector.

The TPM2 key protector registers two commands:

- tpm2_key_protector_init: Initializes the state of the TPM2 key
                           protector for later usage, clearing any
                           previous state, too, if any.

- tpm2_key_protector_clear: Clears any state set by tpm2_key_protector_init.

The way this is expected to be used requires the user to, either
interactively or, normally, via a boot script, initialize (i.e.,
configure) the key protector and then specify that it be used by the
'cryptomount' command (modifications to this command are in a different
patch).

For instance, to unseal the raw sealed key file:

tpm2_key_protector_init --keyfile=(hd0,gpt1)/efi/grub2/sealed-1.key
cryptomount DISK1 -P tpm2

tpm2_key_protector_init --keyfile=(hd0,gpt1)/efi/grub2/sealed-2.key --pcrs=7,11
cryptomount DISK2 -P tpm2

Or, to unseal the TPM 2.0 Key file:

tpm2_key_protector_init --tpm2key=(hd0,gpt1)/efi/grub2/sealed-1.tpm
cryptomount DISK1 -P tpm2

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.

Signed-off-by: Hernan Gatta <hegatta@linux.microsoft.com>
Signed-off-by: Gary Lin <glin@suse.com>
---
 grub-core/Makefile.core.def       |  13 +
 grub-core/tpm2/args.c             | 129 +++++
 grub-core/tpm2/module.c           | 833 ++++++++++++++++++++++++++++++
 grub-core/tpm2/tpm2key.asn        |  31 ++
 grub-core/tpm2/tpm2key.c          | 218 ++++++++
 grub-core/tpm2/tpm2key_asn1_tab.c |  34 ++
 include/grub/tpm2/internal/args.h |  39 ++
 include/grub/tpm2/tpm2key.h       |  40 ++
 8 files changed, 1337 insertions(+)
 create mode 100644 grub-core/tpm2/args.c
 create mode 100644 grub-core/tpm2/module.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/tpm2/internal/args.h
 create mode 100644 include/grub/tpm2/tpm2key.h

diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index 53b680a77..d8c4e92a2 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -2525,6 +2525,19 @@ module = {
   enable = efi;
 };
 
+module = {
+  name = tpm2;
+  common = tpm2/args.c;
+  common = tpm2/buffer.c;
+  common = tpm2/module.c;
+  common = tpm2/mu.c;
+  common = tpm2/tpm2.c;
+  common = tpm2/tpm2key.c;
+  common = tpm2/tpm2key_asn1_tab.c;
+  efi = tpm2/tcg2.c;
+  enable = efi;
+};
+
 module = {
   name = tr;
   common = commands/tr.c;
diff --git a/grub-core/tpm2/args.c b/grub-core/tpm2/args.c
new file mode 100644
index 000000000..49011b377
--- /dev/null
+++ b/grub-core/tpm2/args.c
@@ -0,0 +1,129 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2022 Microsoft Corporation
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/err.h>
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/tpm2/internal/args.h>
+
+grub_err_t
+grub_tpm2_protector_parse_pcrs (char *value, grub_uint8_t *pcrs,
+                               grub_uint8_t *pcr_count)
+{
+  char *current_pcr = value;
+  char *next_pcr;
+  unsigned long pcr;
+  grub_uint8_t i;
+
+  if (grub_strlen (value) == 0)
+    return GRUB_ERR_BAD_ARGUMENT;
+
+  *pcr_count = 0;
+  for (i = 0; i < TPM_MAX_PCRS; i++)
+    {
+      next_pcr = grub_strchr (current_pcr, ',');
+      if (next_pcr == current_pcr)
+       return grub_error (GRUB_ERR_BAD_ARGUMENT,
+                          N_("Empty entry in PCR list"));
+      if (next_pcr)
+       *next_pcr = '\0';
+
+      grub_errno = GRUB_ERR_NONE;
+      pcr = grub_strtoul (current_pcr, NULL, 10);
+      if (grub_errno != GRUB_ERR_NONE)
+       return grub_error (grub_errno,
+                          N_("Entry '%s' in PCR list is not a number"),
+                          current_pcr);
+
+      if (pcr > TPM_MAX_PCRS)
+       return grub_error (GRUB_ERR_OUT_OF_RANGE,
+                          N_("Entry %lu in PCR list is too large to be a PCR "
+                             "number, PCR numbers range from 0 to %u"),
+                          pcr, TPM_MAX_PCRS);
+
+      pcrs[i] = (grub_uint8_t)pcr;
+      *pcr_count += 1;
+
+      if (!next_pcr)
+       break;
+
+      current_pcr = next_pcr + 1;
+      if (*current_pcr == '\0')
+       return grub_error (GRUB_ERR_BAD_ARGUMENT,
+                          N_("Trailing comma at the end of PCR list"));
+    }
+
+  if (i == TPM_MAX_PCRS)
+    return grub_error (GRUB_ERR_OUT_OF_RANGE,
+                      N_("Too many PCRs in PCR list, the maximum number of "
+                         "PCRs is %u"), TPM_MAX_PCRS);
+
+  return GRUB_ERR_NONE;
+}
+
+grub_err_t
+grub_tpm2_protector_parse_asymmetric (const char *value, TPM_ALG_ID 
*asymmetric)
+{
+  if (grub_strcasecmp (value, "ECC") == 0)
+    *asymmetric = TPM_ALG_ECC;
+  else if (grub_strcasecmp (value, "RSA") == 0)
+    *asymmetric = TPM_ALG_RSA;
+  else
+    return grub_error (GRUB_ERR_OUT_OF_RANGE,
+                      N_("Value '%s' is not a valid asymmetric key type"),
+                      value);
+
+  return GRUB_ERR_NONE;
+}
+
+grub_err_t
+grub_tpm2_protector_parse_bank (const char *value, TPM_ALG_ID *bank)
+{
+  if (grub_strcasecmp (value, "SHA1") == 0)
+    *bank = TPM_ALG_SHA1;
+  else if (grub_strcasecmp (value, "SHA256") == 0)
+    *bank = TPM_ALG_SHA256;
+  else if (grub_strcasecmp (value, "SHA384") == 0)
+    *bank = TPM_ALG_SHA384;
+  else
+    return grub_error (GRUB_ERR_OUT_OF_RANGE,
+                      N_("Value '%s' is not a valid PCR bank"), value);
+
+  return GRUB_ERR_NONE;
+}
+
+grub_err_t
+grub_tpm2_protector_parse_tpm_handle (const char *value, TPM_HANDLE *handle)
+{
+  unsigned long num;
+
+  grub_errno = GRUB_ERR_NONE;
+  num = grub_strtoul (value, NULL, 0);
+  if (grub_errno != GRUB_ERR_NONE)
+    return grub_error (grub_errno, N_("TPM handle value '%s' is not a number"),
+                      value);
+
+  if (num > GRUB_UINT_MAX)
+    return grub_error (GRUB_ERR_OUT_OF_RANGE,
+                      N_("Value %lu is too large to be a TPM handle, TPM "
+                         "handles are unsigned 32-bit integers"), num);
+
+  *handle = (TPM_HANDLE)num;
+
+  return GRUB_ERR_NONE;
+}
diff --git a/grub-core/tpm2/module.c b/grub-core/tpm2/module.c
new file mode 100644
index 000000000..7bb58e3fd
--- /dev/null
+++ b/grub-core/tpm2/module.c
@@ -0,0 +1,833 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2022 Microsoft Corporation
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/dl.h>
+#include <grub/extcmd.h>
+#include <grub/file.h>
+#include <grub/libtasn1.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/mu.h>
+#include <grub/tpm2/tpm2.h>
+#include <grub/tpm2/tpm2key.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+typedef enum grub_tpm2_protector_mode
+{
+  GRUB_TPM2_PROTECTOR_MODE_UNSET,
+  GRUB_TPM2_PROTECTOR_MODE_SRK,
+  GRUB_TPM2_PROTECTOR_MODE_NV
+} grub_tpm2_protector_mode_t;
+
+enum grub_tpm2_protector_options
+{
+  OPTION_MODE,
+  OPTION_PCRS,
+  OPTION_BANK,
+  OPTION_TPM2KEY,
+  OPTION_KEYFILE,
+  OPTION_SRK,
+  OPTION_ASYMMETRIC,
+  OPTION_NVINDEX
+};
+
+struct grub_tpm2_protector_context
+{
+  grub_tpm2_protector_mode_t mode;
+  grub_uint8_t pcrs[TPM_MAX_PCRS];
+  grub_uint8_t pcr_count;
+  TPM_ALG_ID asymmetric;
+  TPM_ALG_ID bank;
+  const char *tpm2key;
+  const char *keyfile;
+  TPM_HANDLE srk;
+  TPM_HANDLE nv;
+};
+
+static const struct grub_arg_option grub_tpm2_protector_init_cmd_options[] =
+  {
+    /* Options for all modes */
+    {
+      .longarg  = "mode",
+      .shortarg = 'm',
+      .flags    = 0,
+      .arg      = NULL,
+      .type     = ARG_TYPE_STRING,
+      .doc      =
+       N_("Unseal key using SRK ('srk') (default) or retrieve it from an NV "
+          "Index ('nv')."),
+    },
+    {
+      .longarg  = "pcrs",
+      .shortarg = 'p',
+      .flags    = 0,
+      .arg      = NULL,
+      .type     = ARG_TYPE_STRING,
+      .doc      =
+       N_("Comma-separated list of PCRs used to authorize key release "
+          "(e.g., '7,11', default is 7."),
+    },
+    {
+      .longarg  = "bank",
+      .shortarg = 'b',
+      .flags    = 0,
+      .arg      = NULL,
+      .type     = ARG_TYPE_STRING,
+      .doc      =
+       N_("Bank of PCRs used to authorize key release: "
+          "SHA1, SHA256 (default), or SHA384."),
+    },
+    /* SRK-mode options */
+    {
+      .longarg  = "tpm2key",
+      .shortarg = 'T',
+      .flags    = 0,
+      .arg      = NULL,
+      .type     = ARG_TYPE_STRING,
+      .doc      =
+       N_("Required in SRK mode, path to the key file in TPM 2.0 Key File 
Format "
+          "to unseal using the TPM (e.g., (hd0,gpt1)/boot/grub2/secret.tpm)."),
+    },
+    {
+      .longarg  = "keyfile",
+      .shortarg = 'k',
+      .flags    = 0,
+      .arg      = NULL,
+      .type     = ARG_TYPE_STRING,
+      .doc      =
+       N_("Required in SRK mode, path to the sealed key file to unseal using "
+          "the TPM (e.g., (hd0,gpt1)/boot/grub2/sealed_key). "
+           "Use '-tpm2key' instead"),
+    },
+    {
+      .longarg  = "srk",
+      .shortarg = 's',
+      .flags    = 0,
+      .arg      = NULL,
+      .type     = ARG_TYPE_STRING,
+      .doc      =
+       N_("In SRK mode, the SRK handle if the SRK is persistent "
+          "(default is 0x81000001)."),
+    },
+    {
+      .longarg  = "asymmetric",
+      .shortarg = 'a',
+      .flags    = 0,
+      .arg      = NULL,
+      .type     = ARG_TYPE_STRING,
+      .doc      =
+       N_("In SRK mode, the type of SRK: RSA (default) or ECC."),
+    },
+    /* NV Index-mode options */
+    {
+      .longarg  = "nvindex",
+      .shortarg = 'n',
+      .flags    = 0,
+      .arg      = NULL,
+      .type     = ARG_TYPE_STRING,
+      .doc      =
+       N_("Required in NV Index mode, the NV handle to read which must "
+          "readily exist on the TPM and which contains the key."),
+    },
+    /* End of list */
+    {0, 0, 0, 0, 0, 0}
+  };
+
+static grub_extcmd_t grub_tpm2_protector_init_cmd;
+static grub_extcmd_t grub_tpm2_protector_clear_cmd;
+static struct grub_tpm2_protector_context grub_tpm2_protector_ctx = { 0 };
+
+static grub_err_t
+grub_tpm2_protector_srk_read_file (const char *filepath, void **buffer,
+                                  grub_size_t *buffer_size)
+{
+  grub_file_t file;
+  grub_off_t file_size;
+  void *read_buffer;
+  grub_off_t read_n;
+
+  /* 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)
+    {
+      grub_dprintf ("tpm2", "Could not open file: %s\n", filepath);
+      /* grub_file_open sets grub_errno on error, and if we do no unset it,
+       * future calls to grub_file_open will fail (and so will anybody up the
+       * stack who checks the value, if any). */
+      grub_errno = GRUB_ERR_NONE;
+      return GRUB_ERR_FILE_NOT_FOUND;
+    }
+
+  file_size = grub_file_size (file);
+  if (!file_size)
+    {
+      grub_dprintf ("tpm2", "Could not read file size: %s\n", filepath);
+      grub_file_close (file);
+      return GRUB_ERR_OUT_OF_RANGE;
+    }
+
+  read_buffer = grub_malloc (file_size);
+  if (!read_buffer)
+    {
+      grub_dprintf ("tpm2", "Could not allocate buffer for %s.\n", filepath);
+      grub_file_close (file);
+      return GRUB_ERR_OUT_OF_MEMORY;
+    }
+
+  read_n = grub_file_read (file, read_buffer, file_size);
+  if (read_n != file_size)
+    {
+      grub_dprintf ("tpm2", "Could not retrieve file contents: %s\n", 
filepath);
+      grub_free (read_buffer);
+      grub_file_close (file);
+      return GRUB_ERR_FILE_READ_ERROR;
+    }
+
+  grub_file_close (file);
+
+  *buffer = read_buffer;
+  *buffer_size = file_size;
+
+  return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_tpm2_protector_srk_unmarshal_keyfile (void *sealed_key,
+                                          grub_size_t sealed_key_size,
+                                          TPM2_SEALED_KEY *sk)
+{
+  struct grub_tpm2_buffer buf;
+
+  grub_tpm2_buffer_init (&buf);
+  if (sealed_key_size > buf.cap)
+    {
+      grub_dprintf ("tpm2", "Sealed key file is larger than decode buffer "
+                           "(%" PRIuGRUB_SIZE " vs %" PRIuGRUB_SIZE " 
bytes).\n", sealed_key_size, buf.cap);
+      return GRUB_ERR_BAD_ARGUMENT;
+    }
+
+  grub_memcpy (buf.data, sealed_key, sealed_key_size);
+  buf.size = sealed_key_size;
+
+  grub_tpm2_mu_TPM2B_PUBLIC_Unmarshal (&buf, &sk->public);
+  grub_tpm2_mu_TPM2B_Unmarshal (&buf, (TPM2B *)&sk->private);
+
+  if (buf.error)
+    {
+      grub_dprintf ("tpm2", "Could not unmarshal sealed key file, it is likely 
"
+                           "malformed.\n");
+      return GRUB_ERR_BAD_ARGUMENT;
+    }
+
+  return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_tpm2_protector_srk_unmarshal_tpm2key (void *sealed_key,
+                                          grub_size_t sealed_key_size,
+                                          grub_uint32_t *parent,
+                                          TPM2_SEALED_KEY *sk)
+{
+  asn1_node tpm2key = NULL;
+  grub_uint32_t parent_tmp;
+  void *sealed_pub = NULL;
+  grub_size_t sealed_pub_size;
+  void *sealed_priv = NULL;
+  grub_size_t sealed_priv_size;
+  struct grub_tpm2_buffer buf;
+  grub_err_t err;
+
+  err = grub_tpm2key_start_parsing (&tpm2key, sealed_key, sealed_key_size);
+  if (err != GRUB_ERR_NONE)
+    return err;
+
+  err = grub_tpm2key_get_parent (tpm2key, &parent_tmp);
+  if (err != GRUB_ERR_NONE)
+    goto error;
+  *parent = parent_tmp;
+
+  err = grub_tpm2key_get_pubkey (tpm2key, &sealed_pub, &sealed_pub_size);
+  if (err != GRUB_ERR_NONE)
+    goto error;
+
+  err = grub_tpm2key_get_privkey (tpm2key, &sealed_priv, &sealed_priv_size);
+  if (err != GRUB_ERR_NONE)
+    goto error;
+
+  grub_tpm2_buffer_init (&buf);
+  if (sealed_pub_size + sealed_priv_size > buf.cap)
+    {
+      grub_dprintf ("tpm2", "Sealed key is larger than decode buffer "
+                           "(%" PRIuGRUB_SIZE " vs %" PRIuGRUB_SIZE " 
bytes).\n", sealed_pub_size, buf.cap);
+      err = GRUB_ERR_BAD_ARGUMENT;
+      goto error;
+    }
+
+  grub_tpm2_buffer_pack (&buf, sealed_pub, sealed_pub_size);
+  grub_tpm2_buffer_pack (&buf, sealed_priv, sealed_priv_size);
+
+  buf.offset = 0;
+
+  grub_tpm2_mu_TPM2B_PUBLIC_Unmarshal (&buf, &sk->public);
+  grub_tpm2_mu_TPM2B_Unmarshal (&buf, (TPM2B *)&sk->private);
+
+  if (buf.error)
+    {
+      grub_dprintf ("tpm2", "Could not unmarshal sealed key, it is likely "
+                           "malformed.\n");
+      err = GRUB_ERR_BAD_ARGUMENT;
+      goto error;
+    }
+
+  err = GRUB_ERR_NONE;
+
+error:
+  grub_tpm2key_end_parsing (tpm2key);
+  grub_free (sealed_pub);
+  grub_free (sealed_priv);
+
+  return err;
+}
+
+static grub_err_t
+grub_tpm2_protector_srk_get (const struct grub_tpm2_protector_context *ctx,
+                            TPM_HANDLE parent, TPM_HANDLE *srk)
+{
+  TPM_RC rc;
+  TPM2B_PUBLIC public;
+  TPMS_AUTH_COMMAND authCommand = { 0 };
+  TPM2B_SENSITIVE_CREATE inSensitive = { 0 };
+  TPM2B_PUBLIC inPublic = { 0 };
+  TPM2B_DATA outsideInfo = { 0 };
+  TPML_PCR_SELECTION creationPcr = { 0 };
+  TPM2B_PUBLIC outPublic = { 0 };
+  TPM2B_CREATION_DATA creationData = { 0 };
+  TPM2B_DIGEST creationHash = { 0 };
+  TPMT_TK_CREATION creationTicket = { 0 };
+  TPM2B_NAME srkName = { 0 };
+  TPM_HANDLE srkHandle;
+
+  /* Find SRK */
+  rc = TPM2_ReadPublic (ctx->srk, NULL, &public);
+  if (rc == TPM_RC_SUCCESS)
+    {
+      *srk = ctx->srk;
+      return GRUB_ERR_NONE;
+    }
+
+  /* The handle exists but its public area could not be read. */
+  if ((rc & ~TPM_RC_N_MASK) != TPM_RC_HANDLE)
+    {
+      grub_dprintf ("tpm2", "The SRK handle (0x%x) exists on the TPM but its "
+                           "public area could not be read (TPM2_ReadPublic "
+                           "failed with TSS/TPM error %u).\n", ctx->srk, rc);
+      return GRUB_ERR_BAD_DEVICE;
+    }
+
+  /* Create SRK */
+  authCommand.sessionHandle = TPM_RS_PW;
+  inPublic.publicArea.type = ctx->asymmetric;
+  inPublic.publicArea.nameAlg  = TPM_ALG_SHA256;
+  inPublic.publicArea.objectAttributes.restricted = 1;
+  inPublic.publicArea.objectAttributes.userWithAuth = 1;
+  inPublic.publicArea.objectAttributes.decrypt = 1;
+  inPublic.publicArea.objectAttributes.fixedTPM = 1;
+  inPublic.publicArea.objectAttributes.fixedParent = 1;
+  inPublic.publicArea.objectAttributes.sensitiveDataOrigin = 1;
+  inPublic.publicArea.objectAttributes.noDA = 1;
+
+  if (ctx->asymmetric == TPM_ALG_RSA)
+    {
+      inPublic.publicArea.parameters.rsaDetail.symmetric.algorithm = 
TPM_ALG_AES;
+      inPublic.publicArea.parameters.rsaDetail.symmetric.keyBits.aes = 128;
+      inPublic.publicArea.parameters.rsaDetail.symmetric.mode.aes = 
TPM_ALG_CFB;
+      inPublic.publicArea.parameters.rsaDetail.scheme.scheme = TPM_ALG_NULL;
+      inPublic.publicArea.parameters.rsaDetail.keyBits = 2048;
+      inPublic.publicArea.parameters.rsaDetail.exponent = 0;
+    }
+  else if (ctx->asymmetric == TPM_ALG_ECC)
+    {
+      inPublic.publicArea.parameters.eccDetail.symmetric.algorithm = 
TPM_ALG_AES;
+      inPublic.publicArea.parameters.eccDetail.symmetric.keyBits.aes = 128;
+      inPublic.publicArea.parameters.eccDetail.symmetric.mode.aes = 
TPM_ALG_CFB;
+      inPublic.publicArea.parameters.eccDetail.scheme.scheme = TPM_ALG_NULL;
+      inPublic.publicArea.parameters.eccDetail.curveID = TPM_ECC_NIST_P256;
+      inPublic.publicArea.parameters.eccDetail.kdf.scheme = TPM_ALG_NULL;
+    }
+  else
+    return GRUB_ERR_BAD_ARGUMENT;
+
+  rc = TPM2_CreatePrimary (parent, &authCommand, &inSensitive, &inPublic,
+                          &outsideInfo, &creationPcr, &srkHandle, &outPublic,
+                          &creationData, &creationHash, &creationTicket,
+                          &srkName, NULL);
+  if (rc != TPM_RC_SUCCESS)
+    {
+      grub_dprintf ("tpm2", "Could not create SRK (TPM2_CreatePrimary failed "
+                           "with TSS/TPM error %u).\n", rc);
+      return GRUB_ERR_BAD_DEVICE;
+    }
+
+  *srk = srkHandle;
+
+  return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_tpm2_protector_srk_recover (const struct grub_tpm2_protector_context *ctx,
+                                grub_uint8_t **key, grub_size_t *key_size)
+{
+  TPM_RC rc;
+  TPM2_SEALED_KEY sealed_key;
+  void *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 = {
+    .count = 1,
+    .pcrSelections = {
+      {
+       .hash = ctx->bank,
+       .sizeOfSelect = 3,
+       .pcrSelect = { 0 }
+      },
+    }
+  };
+  TPMS_AUTH_COMMAND authCmd = { 0 };
+  TPM_HANDLE sealed_key_handle;
+  TPM2B_NAME name;
+  TPM2B_SENSITIVE_DATA data;
+  grub_uint8_t *key_out;
+  grub_uint8_t i;
+  grub_err_t err;
+
+  /* Retrieve Sealed Key */
+  if (ctx->tpm2key)
+    {
+      err = grub_tpm2_protector_srk_read_file (ctx->tpm2key, &file_bytes,
+                                              &file_size);
+      if (err)
+       return grub_error (err, N_("Failed to read key file %s"), ctx->tpm2key);
+
+      err = grub_tpm2_protector_srk_unmarshal_tpm2key (file_bytes,
+                                                      file_size,
+                                                      &parent_handle,
+                                                      &sealed_key);
+      if (err)
+       {
+         grub_error (err, N_("Failed to unmarshal key, ensure the key file is 
in "
+                     "TPM wire format"));
+         goto exit1;
+       }
+    }
+  else
+    {
+      err = grub_tpm2_protector_srk_read_file (ctx->keyfile, &file_bytes,
+                                              &file_size);
+      if (err)
+       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)
+       {
+         grub_error (err, N_("Failed to unmarshal key, ensure the key file is 
in "
+                     "TPM wire format"));
+         goto exit1;
+       }
+    }
+
+  /* Get SRK */
+  err = grub_tpm2_protector_srk_get (ctx, parent_handle, &srk_handle);
+  if (err)
+    {
+      grub_error (err, N_("Failed to retrieve the SRK"));
+      goto exit1;
+    }
+
+  err = GRUB_ERR_BAD_DEVICE;
+
+  /* Start Auth Session */
+  nonceCaller.size = TPM_SHA256_DIGEST_SIZE;
+  symmetric.algorithm = TPM_ALG_NULL;
+
+  rc = TPM2_StartAuthSession (TPM_RH_NULL, TPM_RH_NULL, NULL, &nonceCaller, 
NULL,
+                             TPM_SE_POLICY, &symmetric, TPM_ALG_SHA256,
+                             &session, NULL, NULL);
+  if (rc)
+    {
+      grub_error (err, N_("Failed to start auth session (TPM2_StartAuthSession 
"
+                         "failed with TSS/TPM error %u)"), rc);
+      goto exit2;
+    }
+
+  /* Policy PCR */
+  for (i = 0; i < ctx->pcr_count; i++)
+    pcrSel
+      .pcrSelections[0]
+      .pcrSelect[TPM2_PCR_TO_SELECT(ctx->pcrs[i])]
+       |= TPM2_PCR_TO_BIT(ctx->pcrs[i]);
+
+  rc = TPM2_PolicyPCR (session, NULL, NULL, &pcrSel, NULL);
+  if (rc)
+    {
+      grub_error (err, N_("Failed to submit PCR policy (TPM2_PolicyPCR failed "
+                         "with TSS/TPM error %u)"), rc);
+      goto exit3;
+    }
+
+  /* Load Sealed Key */
+  authCmd.sessionHandle = TPM_RS_PW;
+  rc = TPM2_Load (srk_handle, &authCmd, &sealed_key.private, 
&sealed_key.public,
+                 &sealed_key_handle, &name, 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)
+    {
+      grub_error (err, N_("Failed to unseal sealed key (TPM2_Unseal failed "
+                         "with TSS/TPM error %u)"), rc);
+      goto exit4;
+    }
+
+  /* Epilogue */
+  key_out = grub_malloc (data.size);
+  if (!key_out)
+    {
+      err = GRUB_ERR_OUT_OF_MEMORY;
+      grub_error (err, N_("No memory left to allocate unlock key buffer"));
+      goto exit4;
+    }
+
+  grub_memcpy (key_out, data.buffer, data.size);
+
+  *key = key_out;
+  *key_size = data.size;
+
+  err = GRUB_ERR_NONE;
+
+exit4:
+  TPM2_FlushContext (sealed_key_handle);
+
+exit3:
+  TPM2_FlushContext (session);
+
+exit2:
+  TPM2_FlushContext (srk_handle);
+
+exit1:
+  grub_free (file_bytes);
+  return err;
+}
+
+static grub_err_t
+grub_tpm2_protector_nv_recover (const struct grub_tpm2_protector_context *ctx,
+                               grub_uint8_t **key, grub_size_t *key_size)
+{
+  (void)ctx;
+  (void)key;
+  (void)key_size;
+
+  return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+                    N_("NV Index mode is not implemented yet"));
+}
+
+static grub_err_t
+grub_tpm2_protector_recover (const struct grub_tpm2_protector_context *ctx,
+                            grub_uint8_t **key, grub_size_t *key_size)
+{
+  switch (ctx->mode)
+    {
+    case GRUB_TPM2_PROTECTOR_MODE_SRK:
+      return grub_tpm2_protector_srk_recover (ctx, key, key_size);
+    case GRUB_TPM2_PROTECTOR_MODE_NV:
+      return grub_tpm2_protector_nv_recover (ctx, key, key_size);
+    default:
+      return GRUB_ERR_BAD_ARGUMENT;
+    }
+}
+
+static grub_err_t
+grub_tpm2_protector_recover_key (grub_uint8_t **key, grub_size_t *key_size)
+{
+  grub_err_t err;
+
+  /* Expect a call to tpm2_protector_init before anybody tries to use us */
+  if (grub_tpm2_protector_ctx.mode == GRUB_TPM2_PROTECTOR_MODE_UNSET)
+    return grub_error (GRUB_ERR_INVALID_COMMAND,
+                      N_("Cannot use TPM2 key protector without initializing "
+                         "it, call tpm2_protector_init first"));
+
+  if (!key)
+    return GRUB_ERR_BAD_ARGUMENT;
+
+  err = grub_tpm2_protector_recover (&grub_tpm2_protector_ctx, key, key_size);
+  if (err)
+    return err;
+
+  return GRUB_ERR_NONE;
+}
+
+
+static grub_err_t
+grub_tpm2_protector_check_args (struct grub_tpm2_protector_context *ctx)
+{
+  if (ctx->mode == GRUB_TPM2_PROTECTOR_MODE_UNSET)
+    ctx->mode = GRUB_TPM2_PROTECTOR_MODE_SRK;
+
+  /* Checks for SRK mode */
+  if (ctx->mode == GRUB_TPM2_PROTECTOR_MODE_SRK && !ctx->keyfile
+      && !ctx->tpm2key)
+    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->nv)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT,
+                      N_("In SRK mode, an NV Index cannot be specified"));
+
+  /* Checks for NV mode */
+  if (ctx->mode == GRUB_TPM2_PROTECTOR_MODE_NV && !ctx->nv)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT,
+                      N_("In NV Index mode, an NV Index must be specified: "
+                          "--nvindex or -n"));
+
+  if (ctx->mode == GRUB_TPM2_PROTECTOR_MODE_NV &&
+      (ctx->tpm2key || ctx->keyfile))
+    return grub_error (GRUB_ERR_BAD_ARGUMENT,
+                      N_("In NV Index mode, a keyfile cannot be specified"));
+
+  if (ctx->mode == GRUB_TPM2_PROTECTOR_MODE_NV && ctx->srk)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT,
+                      N_("In NV Index mode, an SRK cannot be specified"));
+
+  if (ctx->mode == GRUB_TPM2_PROTECTOR_MODE_NV && ctx->asymmetric)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT,
+                      N_("In NV Index mode, an asymmetric key type cannot be "
+                         "specified"));
+
+  /* Defaults assignment */
+  if (!ctx->bank)
+    ctx->bank = TPM_ALG_SHA256;
+
+  if (!ctx->pcr_count)
+    {
+      ctx->pcrs[0] = 7;
+      ctx->pcr_count = 1;
+    }
+
+  if (ctx->mode == GRUB_TPM2_PROTECTOR_MODE_SRK)
+    {
+      if (!ctx->srk)
+       ctx->srk = TPM2_SRK_HANDLE;
+
+      if (!ctx->asymmetric)
+       ctx->asymmetric = TPM_ALG_RSA;
+    }
+
+  return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_tpm2_protector_parse_file (const char *value, const char **file)
+{
+  if (grub_strlen (value) == 0)
+    return GRUB_ERR_BAD_ARGUMENT;
+
+  *file = grub_strdup (value);
+  if (!*file)
+    return grub_error (GRUB_ERR_OUT_OF_MEMORY,
+                      N_("No memory to duplicate file path"));
+
+  return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_tpm2_protector_parse_mode (const char *value,
+                               grub_tpm2_protector_mode_t *mode)
+{
+  if (grub_strcmp (value, "srk") == 0)
+    *mode = GRUB_TPM2_PROTECTOR_MODE_SRK;
+  else if (grub_strcmp (value, "nv") == 0)
+    *mode = GRUB_TPM2_PROTECTOR_MODE_NV;
+  else
+    return grub_error (GRUB_ERR_OUT_OF_RANGE,
+                      N_("Value '%s' is not a valid TPM2 key protector mode"),
+                      value);
+
+  return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_tpm2_protector_init_cmd_handler (grub_extcmd_context_t ctxt, int argc,
+                                char **args __attribute__ ((unused)))
+{
+  struct grub_arg_list *state = ctxt->state;
+  grub_err_t err;
+
+  if (argc)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT,
+                      N_("The TPM2 key protector does not accept any "
+                         "non-option arguments (i.e., like -o and/or --option "
+                         "only)"));
+
+  grub_free ((void *) grub_tpm2_protector_ctx.keyfile);
+  grub_memset (&grub_tpm2_protector_ctx, 0, sizeof (grub_tpm2_protector_ctx));
+
+  if (state[OPTION_MODE].set)  /* mode */
+    {
+      err = grub_tpm2_protector_parse_mode (state[OPTION_MODE].arg,
+                                           &grub_tpm2_protector_ctx.mode);
+      if (err)
+       return err;
+    }
+
+  if (state[OPTION_PCRS].set)  /* pcrs */
+    {
+      err = grub_tpm2_protector_parse_pcrs (state[OPTION_PCRS].arg,
+                                           grub_tpm2_protector_ctx.pcrs,
+                                           &grub_tpm2_protector_ctx.pcr_count);
+      if (err)
+       return err;
+    }
+
+  if (state[OPTION_BANK].set)  /* bank */
+    {
+      err = grub_tpm2_protector_parse_bank (state[OPTION_BANK].arg,
+                                           &grub_tpm2_protector_ctx.bank);
+      if (err)
+       return err;
+    }
+
+  if (state[OPTION_TPM2KEY].set)  /* tpm2key */
+    {
+      err = grub_tpm2_protector_parse_file (state[OPTION_TPM2KEY].arg,
+                                           &grub_tpm2_protector_ctx.tpm2key);
+      if (err)
+       return err;
+    }
+
+  if (state[OPTION_KEYFILE].set)  /* keyfile */
+    {
+      err = grub_tpm2_protector_parse_file (state[OPTION_KEYFILE].arg,
+                                           &grub_tpm2_protector_ctx.keyfile);
+      if (err)
+       return err;
+    }
+
+  if (state[OPTION_SRK].set)  /* srk */
+    {
+      err = grub_tpm2_protector_parse_tpm_handle (state[OPTION_SRK].arg,
+                                                 &grub_tpm2_protector_ctx.srk);
+      if (err)
+       return err;
+    }
+
+  if (state[OPTION_ASYMMETRIC].set)  /* asymmetric */
+    {
+      err = grub_tpm2_protector_parse_asymmetric (state[OPTION_ASYMMETRIC].arg,
+                                                 
&grub_tpm2_protector_ctx.asymmetric);
+      if (err)
+       return err;
+    }
+
+  if (state[OPTION_NVINDEX].set)  /* nvindex */
+    {
+      err = grub_tpm2_protector_parse_tpm_handle (state[OPTION_NVINDEX].arg,
+                                                 &grub_tpm2_protector_ctx.nv);
+      if (err)
+       return err;
+    }
+
+  err = grub_tpm2_protector_check_args (&grub_tpm2_protector_ctx);
+
+  /* This command only initializes the protector, so nothing else to do. */
+
+  return err;
+}
+
+static grub_err_t
+grub_tpm2_protector_clear_cmd_handler (grub_extcmd_context_t ctxt 
__attribute__ ((unused)),
+                                      int argc,
+                                      char **args __attribute__ ((unused)))
+{
+  if (argc)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT,
+                      N_("tpm2_key_protector_clear accepts no arguments"));
+
+  grub_free ((void *) grub_tpm2_protector_ctx.keyfile);
+  grub_memset (&grub_tpm2_protector_ctx, 0, sizeof (grub_tpm2_protector_ctx));
+
+  return GRUB_ERR_NONE;
+}
+
+static struct grub_key_protector grub_tpm2_key_protector =
+  {
+    .name = "tpm2",
+    .recover_key = grub_tpm2_protector_recover_key
+  };
+
+GRUB_MOD_INIT (tpm2)
+{
+  grub_tpm2_protector_init_cmd =
+    grub_register_extcmd ("tpm2_key_protector_init",
+                         grub_tpm2_protector_init_cmd_handler, 0,
+                         N_("[-m mode] "
+                            "[-p pcr_list] "
+                            "[-b pcr_bank] "
+                            "[-T tpm2_key_file_path] "
+                            "[-k sealed_key_file_path] "
+                            "[-s srk_handle] "
+                            "[-a asymmetric_key_type] "
+                            "[-n nv_index]"),
+                         N_("Initialize the TPM2 key protector."),
+                         grub_tpm2_protector_init_cmd_options);
+  grub_tpm2_protector_clear_cmd =
+    grub_register_extcmd ("tpm2_key_protector_clear",
+                         grub_tpm2_protector_clear_cmd_handler, 0, NULL,
+                         N_("Clear the TPM2 key protector if previously 
initialized."),
+                         NULL);
+  grub_key_protector_register (&grub_tpm2_key_protector);
+}
+
+GRUB_MOD_FINI (tpm2)
+{
+  grub_free ((void *) grub_tpm2_protector_ctx.keyfile);
+  grub_memset (&grub_tpm2_protector_ctx, 0, sizeof (grub_tpm2_protector_ctx));
+
+  grub_key_protector_unregister (&grub_tpm2_key_protector);
+  grub_unregister_extcmd (grub_tpm2_protector_clear_cmd);
+  grub_unregister_extcmd (grub_tpm2_protector_init_cmd);
+}
diff --git a/grub-core/tpm2/tpm2key.asn b/grub-core/tpm2/tpm2key.asn
new file mode 100644
index 000000000..e3b6a03e0
--- /dev/null
+++ b/grub-core/tpm2/tpm2key.asn
@@ -0,0 +1,31 @@
+--
+-- TPM 2.0 key file format
+--  To generate tpm2key_asn1_tab.c: asn1Parser tpm2key.asn
+--
+TPM2KEY {}
+DEFINITIONS IMPLICIT TAGS ::=
+
+BEGIN
+
+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
+}
+
+END
diff --git a/grub-core/tpm2/tpm2key.c b/grub-core/tpm2/tpm2key.c
new file mode 100644
index 000000000..8c6845088
--- /dev/null
+++ b/grub-core/tpm2/tpm2key.c
@@ -0,0 +1,218 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2023 SUSE LLC
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/libtasn1.h>
+#include <grub/tpm2/tpm2key.h>
+
+extern asn1_static_node tpm2key_asn1_tab[];
+const char *sealed_key_oid = "2.23.133.10.1.5";
+
+static int
+asn1_allocate_and_read (asn1_node node, const char *name, void **content, 
grub_size_t *content_size)
+{
+  grub_uint8_t *tmpstr = NULL;
+  int tmpstr_size = 0;
+  int ret;
+
+  if (content == NULL)
+    return ASN1_MEM_ERROR;
+
+  ret = asn1_read_value (node, name, NULL, &tmpstr_size);
+  if (ret != ASN1_MEM_ERROR)
+    return ret;
+
+  tmpstr = grub_malloc (tmpstr_size);
+  if (tmpstr == NULL)
+    return ASN1_MEM_ERROR;
+
+  ret = asn1_read_value (node, name, tmpstr, &tmpstr_size);
+  if (ret != ASN1_SUCCESS)
+    return ret;
+
+  *content = tmpstr;
+  *content_size = tmpstr_size;
+
+  return ASN1_SUCCESS;
+}
+
+static int
+asn1_read_uint32 (asn1_node node, const char *name, grub_uint32_t *out)
+{
+  grub_uint32_t tmp = 0;
+  grub_uint8_t *ptr;
+  void *data = NULL;
+  grub_size_t data_size;
+  int ret;
+
+  ret = asn1_allocate_and_read (node, name, &data, &data_size);
+  if (ret != ASN1_SUCCESS)
+    return ret;
+
+  if (data_size > 4)
+    {
+      ret = ASN1_MEM_ERROR;
+      goto error;
+    }
+
+  /* convert the big-endian integer to host uint32 */
+  ptr = (grub_uint8_t *)&tmp + (4 - data_size);
+  grub_memcpy (ptr, data, data_size);
+  tmp = grub_be_to_cpu32 (tmp);
+
+  *out = tmp;
+error:
+  if (data)
+    grub_free (data);
+  return ret;
+}
+
+grub_err_t
+grub_tpm2key_start_parsing (asn1_node *parsed_tpm2key, void *data, grub_size_t 
size)
+{
+  asn1_node tpm2key;
+  asn1_node tpm2key_asn1 = NULL;
+  void *type_oid = NULL;
+  grub_size_t type_oid_size = 0;
+  void *empty_auth = NULL;
+  grub_size_t empty_auth_size = 0;
+  int tmp_size = 0;
+  int ret;
+  grub_err_t err;
+
+  /*
+    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
+    }
+  */
+  ret = asn1_array2tree (tpm2key_asn1_tab, &tpm2key_asn1, NULL);
+  if (ret != ASN1_SUCCESS)
+    return GRUB_ERR_BAD_ARGUMENT;
+
+  ret = asn1_create_element (tpm2key_asn1, "TPM2KEY.TPMKey", &tpm2key);
+  if (ret != ASN1_SUCCESS)
+    return GRUB_ERR_BAD_ARGUMENT;
+
+  ret = asn1_der_decoding (&tpm2key, data, size, NULL);
+  if (ret != ASN1_SUCCESS)
+    return GRUB_ERR_BAD_ARGUMENT;
+
+  /* Check if 'type' is Sealed Key or not */
+  ret = asn1_allocate_and_read (tpm2key, "type", &type_oid, &type_oid_size);
+  if (ret != ASN1_SUCCESS)
+    return GRUB_ERR_BAD_FILE_TYPE;
+
+  if (grub_memcmp (sealed_key_oid, type_oid, type_oid_size) != 0)
+    {
+      err = GRUB_ERR_BAD_FILE_TYPE;
+      goto error;
+    }
+
+  /* 'emptyAuth' must be 'TRUE' since we don't support password authorization 
*/
+  ret = asn1_allocate_and_read (tpm2key, "emptyAuth", &empty_auth, 
&empty_auth_size);
+  if (ret != ASN1_SUCCESS || grub_strncmp ("TRUE", empty_auth, 
empty_auth_size) != 0)
+    {
+      err = GRUB_ERR_BAD_ARGUMENT;
+      goto error;
+    }
+
+  /* 'secret' should not be in a sealed key */
+  ret = asn1_read_value (tpm2key, "secret", NULL, &tmp_size);
+  if (ret != ASN1_ELEMENT_NOT_FOUND)
+    {
+      err = GRUB_ERR_BAD_ARGUMENT;
+      goto error;
+    }
+
+  *parsed_tpm2key = tpm2key;
+
+  err = GRUB_ERR_NONE;
+
+error:
+  if (type_oid)
+    grub_free (type_oid);
+
+  if (empty_auth)
+    grub_free (empty_auth);
+
+  return err;
+}
+
+void
+grub_tpm2key_end_parsing (asn1_node tpm2key)
+{
+  if (tpm2key)
+    asn1_delete_structure (&tpm2key);
+  tpm2key = NULL;
+}
+
+grub_err_t
+grub_tpm2key_get_parent (asn1_node tpm2key, grub_uint32_t *parent)
+{
+  int ret;
+
+  if (parent == NULL)
+    return GRUB_ERR_BAD_ARGUMENT;
+
+  if (tpm2key == NULL)
+    return GRUB_ERR_READ_ERROR;
+
+  ret = asn1_read_uint32 (tpm2key, "parent", parent);
+  if (ret != ASN1_SUCCESS)
+    return GRUB_ERR_READ_ERROR;
+
+  return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+tpm2key_get_octstring (asn1_node tpm2key, const char *name, void **data, 
grub_size_t *size)
+{
+  int ret;
+
+  if (name == NULL || data == NULL || size == NULL)
+    return GRUB_ERR_BAD_ARGUMENT;
+
+  if (tpm2key == NULL)
+    return GRUB_ERR_READ_ERROR;
+
+  ret = asn1_allocate_and_read (tpm2key, name, data, size);
+  if (ret != ASN1_SUCCESS)
+    return GRUB_ERR_READ_ERROR;
+
+  return GRUB_ERR_NONE;
+}
+
+grub_err_t
+grub_tpm2key_get_pubkey (asn1_node tpm2key, void **data, grub_size_t *size)
+{
+  return tpm2key_get_octstring (tpm2key, "pubkey", data, size);
+}
+
+grub_err_t
+grub_tpm2key_get_privkey (asn1_node tpm2key, void **data, grub_size_t *size)
+{
+  return tpm2key_get_octstring (tpm2key, "privkey", data, size);
+}
diff --git a/grub-core/tpm2/tpm2key_asn1_tab.c 
b/grub-core/tpm2/tpm2key_asn1_tab.c
new file mode 100644
index 000000000..3d122444a
--- /dev/null
+++ b/grub-core/tpm2/tpm2key_asn1_tab.c
@@ -0,0 +1,34 @@
+#include <grub/mm.h>
+#include <grub/libtasn1.h>
+
+const asn1_static_node tpm2key_asn1_tab[] = {
+  { "TPM2KEY", 536875024, NULL },
+  { NULL, 1073741836, NULL },
+  { "TPMPolicy", 1610612741, NULL },
+  { "CommandCode", 1610620931, NULL },
+  { NULL, 2056, "0"},
+  { "CommandPolicy", 536879111, NULL },
+  { NULL, 2056, "1"},
+  { "TPMAuthPolicy", 1610612741, NULL },
+  { "Name", 1610637346, NULL },
+  { NULL, 2056, "0"},
+  { "Policy", 536879115, NULL },
+  { NULL, 1073743880, "1"},
+  { NULL, 2, "TPMPolicy"},
+  { "TPMKey", 536870917, NULL },
+  { "type", 1073741836, NULL },
+  { "emptyAuth", 1610637316, NULL },
+  { NULL, 2056, "0"},
+  { "policy", 1610637323, NULL },
+  { NULL, 1073743880, "1"},
+  { NULL, 2, "TPMPolicy"},
+  { "secret", 1610637319, NULL },
+  { NULL, 2056, "2"},
+  { "authPolicy", 1610637323, NULL },
+  { NULL, 1073743880, "3"},
+  { NULL, 2, "TPMAuthPolicy"},
+  { "parent", 1073741827, NULL },
+  { "pubkey", 1073741831, NULL },
+  { "privkey", 7, NULL },
+  { NULL, 0, NULL }
+};
diff --git a/include/grub/tpm2/internal/args.h 
b/include/grub/tpm2/internal/args.h
new file mode 100644
index 000000000..df3341913
--- /dev/null
+++ b/include/grub/tpm2/internal/args.h
@@ -0,0 +1,39 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2022 Microsoft Corporation
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_TPM2_INTERNAL_ARGS_HEADER
+#define GRUB_TPM2_INTERNAL_ARGS_HEADER 1
+
+#include <grub/err.h>
+#include <grub/tpm2/tpm2.h>
+
+grub_err_t
+grub_tpm2_protector_parse_pcrs (char *value, grub_uint8_t *pcrs,
+                               grub_uint8_t *pcr_count);
+
+grub_err_t
+grub_tpm2_protector_parse_asymmetric (const char *value,
+                                     TPM_ALG_ID *asymmetric);
+
+grub_err_t
+grub_tpm2_protector_parse_bank (const char *value, TPM_ALG_ID *bank);
+
+grub_err_t
+grub_tpm2_protector_parse_tpm_handle (const char *value, TPM_HANDLE *handle);
+
+#endif /* ! GRUB_TPM2_INTERNAL_ARGS_HEADER */
diff --git a/include/grub/tpm2/tpm2key.h b/include/grub/tpm2/tpm2key.h
new file mode 100644
index 000000000..e693a38fc
--- /dev/null
+++ b/include/grub/tpm2/tpm2key.h
@@ -0,0 +1,40 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2023 SUSE LLC
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_TPM2_TPM2KEY_HEADER
+#define GRUB_TPM2_TPM2KEY_HEADER 1
+
+#include <grub/types.h>
+#include <grub/libtasn1.h>
+
+grub_err_t
+grub_tpm2key_start_parsing (asn1_node *parsed_tpm2key, void *data, grub_size_t 
size);
+
+void
+grub_tpm2key_end_parsing (asn1_node tpm2key);
+
+grub_err_t
+grub_tpm2key_get_parent (asn1_node tpm2key, grub_uint32_t *parent);
+
+grub_err_t
+grub_tpm2key_get_pubkey (asn1_node tpm2key, void **data, grub_size_t *size);
+
+grub_err_t
+grub_tpm2key_get_privkey (asn1_node tpm2key, void **data, grub_size_t *size);
+
+#endif /* GRUB_TPM2_TPM2KEY_HEADER */
-- 
2.35.3




reply via email to

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