grub-devel
[Top][All Lists]
Advanced

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

[PATCH 5/5] util/grub-protect: Add new tool


From: Hernan Gatta
Subject: [PATCH 5/5] util/grub-protect: Add new tool
Date: Mon, 24 Jan 2022 06:12:18 -0800

From: Hernan Gatta <hegatta@microsoft.com>

To utilize the key protectors framework, there must be a way to protect
full-disk encryption keys in the first place. The grub-protect tool includes
support for the TPM2 key protector but other protectors that require setup ahead
of time can be supported in the future.

For the TPM2 key protector, the intended flow is for a user to have a LUKS 1 or
LUKS 2-protected fully-encrypted disk. The user then creates a new key file, say
by reading /dev/urandom into a file, and creates a new LUKS key slot for this
key. Then, the user invokes the grub-protect tool to seal this key file to a set
of PCRs using the system's TPM 2.0. The resulting sealed key file is stored in
an unencrypted partition such as the EFI System Partition (ESP) so that GRUB may
read it. The user also ensures the cryptomount command is included in GRUB's
boot script and that it carries the requisite --protector (or -p) parameter.

Sample usage:

$ dd if=/dev/urandom of=key count=32
$ sudo cryptsetup luksAddKey /dev/sdb1 key --pbkdf=pbkdf2 --hash=sha512

$ sudo grub-protect --action=add
--protector=tpm2
--tpm2-keyfile=key
--tpm2-outfile=/boot/efi/boot/grub2/sealed_key

Then, in the boot script (wrapped for display):

cryptomount -u b20f95d0834842bc9197bd78b36732f8
-p tpm2:keyfile=(hd0,gpt1)/boot/grub2/sealed_key

where the UUID corresponds to /dev/sdb1.

Signed-off-by: Hernan Gatta <hegatta@linux.microsoft.com>
---
 .gitignore          |    1 +
 Makefile.util.def   |   16 +
 configure.ac        |    1 +
 util/grub-protect.c | 1344 +++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 1362 insertions(+)
 create mode 100644 util/grub-protect.c

diff --git a/.gitignore b/.gitignore
index f6a1bd0..852327d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -167,6 +167,7 @@ widthspec.bin
 /grub-ofpathname.exe
 /grub-probe
 /grub-probe.exe
+/grub-protect
 /grub-reboot
 /grub-render-label
 /grub-render-label.exe
diff --git a/Makefile.util.def b/Makefile.util.def
index 39b53b3..05f9f09 100644
--- a/Makefile.util.def
+++ b/Makefile.util.def
@@ -52,6 +52,9 @@ library = {
   common = grub-core/partmap/msdos.c;
   common = grub-core/fs/proc.c;
   common = grub-core/fs/archelp.c;
+  common = grub-core/tpm2/buffer.c;
+  common = grub-core/tpm2/mu.c;
+  common = grub-core/tpm2/tpm2.c;
 };
 
 library = {
@@ -207,6 +210,19 @@ program = {
 };
 
 program = {
+  name = grub-protect;
+  common = grub-core/osdep/init.c;
+  common = util/grub-protect.c;
+  common = util/probe.c;
+
+  ldadd = libgrubmods.a;
+  ldadd = libgrubgcry.a;
+  ldadd = libgrubkern.a;
+  ldadd = grub-core/lib/gnulib/libgnu.a;
+  ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) 
$(LIBGEOM)';
+};
+
+program = {
   name = grub-mkrelpath;
   mansection = 1;
 
diff --git a/configure.ac b/configure.ac
index 4f649ed..3a4dc5a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -71,6 +71,7 @@ grub_TRANSFORM([grub-mkpasswd-pbkdf2])
 grub_TRANSFORM([grub-mkrelpath])
 grub_TRANSFORM([grub-mkrescue])
 grub_TRANSFORM([grub-probe])
+grub_TRANSFORM([grub-protect])
 grub_TRANSFORM([grub-reboot])
 grub_TRANSFORM([grub-script-check])
 grub_TRANSFORM([grub-set-default])
diff --git a/util/grub-protect.c b/util/grub-protect.c
new file mode 100644
index 0000000..4e4bbd7
--- /dev/null
+++ b/util/grub-protect.c
@@ -0,0 +1,1344 @@
+/*
+ *  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 <config.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <grub/crypto.h>
+#include <grub/emu/getroot.h>
+#include <grub/emu/hostdisk.h>
+#include <grub/emu/misc.h>
+#include <grub/tpm2/buffer.h>
+#include <grub/tpm2/mu.h>
+#include <grub/tpm2/tcg2.h>
+#include <grub/tpm2/tpm2.h>
+#include <grub/util/misc.h>
+
+#include "progname.h"
+
+typedef enum grub_protect_arg
+{
+  GRUB_PROTECT_ARG_ACTION          = 1 << 0,
+  GRUB_PROTECT_ARG_PROTECTOR       = 1 << 1,
+  GRUB_PROTECT_ARG_TPM2_DEVICE     = 1 << 2,
+  GRUB_PROTECT_ARG_TPM2_PCRS       = 1 << 3,
+  GRUB_PROTECT_ARG_TPM2_ASYMMETRIC = 1 << 4,
+  GRUB_PROTECT_ARG_TPM2_BANK       = 1 << 5,
+  GRUB_PROTECT_ARG_TPM2_SRK        = 1 << 6,
+  GRUB_PROTECT_ARG_TPM2_KEYFILE    = 1 << 7,
+  GRUB_PROTECT_ARG_TPM2_OUTFILE    = 1 << 8,
+  GRUB_PROTECT_ARG_TPM2_PERSIST    = 1 << 9,
+  GRUB_PROTECT_ARG_TPM2_EVICT      = 1 << 10
+} grub_protect_arg_t;
+
+typedef enum grub_protect_protector
+{
+  GRUB_PROTECT_TYPE_ERROR,
+  GRUB_PROTECT_TYPE_TPM2
+} grub_protect_protector_t;
+
+typedef enum grub_protect_action
+{
+  GRUB_PROTECT_ACTION_ERROR,
+  GRUB_PROTECT_ACTION_ADD,
+  GRUB_PROTECT_ACTION_REMOVE
+} grub_protect_action_t;
+
+struct grub_protect_args
+{
+  grub_protect_arg_t args;
+  grub_protect_action_t action;
+  grub_protect_protector_t protector;
+
+  const char *tpm2_device;
+  grub_uint8_t tpm2_pcrs[TPM_MAX_PCRS];
+  grub_uint8_t tpm2_pcr_count;
+  TPM_ALG_ID tpm2_asymmetric;
+  TPM_ALG_ID tpm2_bank;
+  TPM_HANDLE tpm2_srk;
+  const char *tpm2_keyfile;
+  const char *tpm2_outfile;
+  int tpm2_persist;
+  int tpm2_evict;
+};
+
+static int tpm2_fd = -1;
+
+static grub_err_t
+grub_protect_read_file (const char *filepath, void **buffer,
+                        size_t *buffer_size)
+{
+  grub_err_t err;
+  FILE *f;
+  long len;
+  void *buf;
+
+  f = fopen (filepath, "rb");
+  if (!f)
+    return GRUB_ERR_FILE_NOT_FOUND;
+
+  if (fseek (f, 0, SEEK_END))
+    {
+       err = GRUB_ERR_FILE_READ_ERROR;
+       goto exit1;
+    }
+
+  len = ftell (f);
+  if (!len)
+    {
+       err = GRUB_ERR_FILE_READ_ERROR;
+       goto exit1;
+    }
+
+  rewind (f);
+
+  buf = grub_malloc (len);
+  if (!buf)
+    {
+       err = GRUB_ERR_OUT_OF_MEMORY;
+       goto exit1;
+    }
+
+  if (fread (buf, len, 1, f) != 1)
+    {
+       err = GRUB_ERR_FILE_READ_ERROR;
+       goto exit2;
+    }
+
+  *buffer = buf;
+  *buffer_size = len;
+
+  buf = NULL;
+  err = GRUB_ERR_NONE;
+
+exit2:
+  grub_free (buf);
+
+exit1:
+  fclose (f);
+
+  return err;
+}
+
+static grub_err_t
+grub_protect_write_file (const char *filepath, void *buffer, size_t 
buffer_size)
+{
+  grub_err_t err;
+  FILE *f;
+
+  f = fopen (filepath, "wb");
+  if (!f)
+    return GRUB_ERR_FILE_NOT_FOUND;
+
+  if (fwrite (buffer, buffer_size, 1, f) != 1)
+  {
+    err = GRUB_ERR_WRITE_ERROR;
+    goto exit1;
+  }
+
+  err = GRUB_ERR_NONE;
+
+exit1:
+  fclose (f);
+
+  return err;
+}
+
+static grub_err_t
+grub_protect_get_grub_drive_for_file (const char *filepath, char **drive)
+{
+  grub_err_t err = GRUB_ERR_IO;
+  char *disk;
+  char **devices;
+  char *grub_dev;
+  char *grub_path;
+  char *efi_drive;
+  char *partition;
+  char *grub_drive;
+  grub_device_t dev;
+  grub_size_t grub_drive_len;
+  int n;
+
+  grub_path = grub_canonicalize_file_name (filepath);
+  if (!grub_path)
+    goto exit1;
+
+  devices = grub_guess_root_devices (grub_path);
+  if (!devices || !devices[0])
+    goto exit2;
+
+  disk = devices[0];
+
+  grub_util_pull_device (disk);
+
+  grub_dev = grub_util_get_grub_dev (disk);
+  if (!grub_dev)
+    goto exit3;
+
+  dev = grub_device_open (grub_dev);
+  if (!dev)
+    goto exit4;
+
+  efi_drive = grub_util_guess_efi_drive (disk);
+  if (!efi_drive)
+    goto exit5;
+
+  partition = grub_partition_get_name (dev->disk->partition);
+  if (!partition)
+    goto exit6;
+
+  grub_drive_len = grub_strlen (efi_drive) + grub_strlen (partition) + 3;
+  grub_drive = grub_malloc (grub_drive_len + 1);
+  if (!grub_drive)
+    goto exit7;
+
+  n = grub_snprintf (grub_drive, grub_drive_len + 1, "(%s,%s)", efi_drive,
+                     partition);
+  if (n != grub_drive_len)
+    goto exit8;
+
+  *drive = grub_drive;
+  grub_drive = NULL;
+  err = GRUB_ERR_NONE;
+
+exit8:
+  grub_free (grub_drive);
+
+exit7:
+  grub_free (partition);
+
+exit6:
+  grub_free (efi_drive);
+
+exit5:
+  grub_device_close (dev);
+
+exit4:
+  grub_free (grub_dev);
+
+exit3:
+  grub_free (devices);
+
+exit2:
+  grub_free (grub_path);
+
+exit1:
+  return err;
+}
+
+grub_err_t
+grub_tcg2_get_max_output_size (grub_size_t *size)
+{
+  if (!size)
+    return GRUB_ERR_BAD_ARGUMENT;
+
+  *size = GRUB_TPM2_BUFFER_CAPACITY;
+
+  return GRUB_ERR_NONE;
+}
+
+grub_err_t
+grub_tcg2_submit_command (grub_size_t input_size, grub_uint8_t *input,
+                          grub_size_t output_size, grub_uint8_t *output)
+{
+  static const grub_size_t header_size = sizeof (grub_uint16_t) +
+                                         (2 * sizeof(grub_uint32_t));
+
+  if (write (tpm2_fd, input, input_size) != input_size)
+    return GRUB_ERR_BAD_DEVICE;
+
+  if (read (tpm2_fd, output, output_size) < header_size)
+    return GRUB_ERR_BAD_DEVICE;
+
+  return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_protect_tpm2_open_device (const char *dev_node)
+{
+  if (tpm2_fd != -1)
+    return GRUB_ERR_NONE;
+
+  tpm2_fd = open (dev_node, O_RDWR);
+  if (tpm2_fd == -1)
+    {
+      fprintf (stderr, _("Could not open TPM device (Error: %u).\n"), errno);
+      return GRUB_ERR_FILE_NOT_FOUND;
+    }
+
+  return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_protect_tpm2_close_device (void)
+{
+  int err;
+
+  if (tpm2_fd == -1)
+    return GRUB_ERR_NONE;
+
+  err = close (tpm2_fd);
+  if (err)
+  {
+    fprintf (stderr, _("Could not close TPM device (Error: %u).\n"), errno);
+    return GRUB_ERR_IO;
+  }
+
+  tpm2_fd = -1;
+  return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_protect_tpm2_get_policy_digest (struct grub_protect_args *args,
+                                     TPM2B_DIGEST *digest)
+{
+  TPM_RC rc;
+  TPML_PCR_SELECTION pcr_sel = {
+    .count = 1,
+    .pcrSelections = {
+      {
+        .hash = args->tpm2_bank,
+        .sizeOfSelect = 3,
+        .pcrSelect = { 0 }
+      },
+    }
+  };
+  TPML_PCR_SELECTION pcr_sel_out = { 0 };
+  TPML_DIGEST pcr_values = { 0 };
+  grub_uint8_t *pcr_digest;
+  grub_size_t pcr_digest_len;
+  grub_uint8_t *pcr_concat;
+  grub_size_t pcr_concat_len;
+  grub_uint8_t *pcr_cursor;
+  const gcry_md_spec_t *hash_spec;
+  TPM2B_NONCE nonce = { 0 };
+  TPM2B_ENCRYPTED_SECRET salt = { 0 };
+  TPMT_SYM_DEF symmetric = { 0 };
+  TPMI_SH_AUTH_SESSION session = 0;
+  TPM2B_DIGEST pcr_digest_in = {
+    .size = TPM_SHA256_DIGEST_SIZE,
+    .buffer = { 0 }
+  };
+  TPM2B_DIGEST policy_digest = { 0 };
+  grub_uint8_t i;
+  grub_err_t err;
+
+  /* PCR Read */
+  for (i = 0; i < args->tpm2_pcr_count; i++)
+    pcr_sel
+      .pcrSelections[0]
+      .pcrSelect[TPM2_PCR_TO_SELECT(args->tpm2_pcrs[i])]
+        |= TPM2_PCR_TO_BIT(args->tpm2_pcrs[i]);
+
+  rc = TPM2_PCR_Read (NULL, &pcr_sel, NULL, &pcr_sel_out, &pcr_values, NULL);
+  if (rc != TPM_RC_SUCCESS)
+    {
+      fprintf (stderr, _("Failed to read PCRs (TPM error: 0x%x).\n"), rc);
+      return GRUB_ERR_BAD_DEVICE;
+    }
+
+  if ((pcr_sel_out.count != pcr_sel.count) ||
+       (pcr_sel.pcrSelections[0].sizeOfSelect !=
+        pcr_sel_out.pcrSelections[0].sizeOfSelect))
+    {
+      fprintf (stderr, _("Could not read all the specified PCRs.\n"));
+      return GRUB_ERR_BAD_DEVICE;
+    }
+
+  /* Compute PCR Digest */
+  switch (args->tpm2_bank)
+    {
+    case TPM_ALG_SHA1:
+      pcr_digest_len = TPM_SHA1_DIGEST_SIZE;
+      hash_spec = GRUB_MD_SHA1;
+      break;
+    case TPM_ALG_SHA256:
+      pcr_digest_len = TPM_SHA256_DIGEST_SIZE;
+      hash_spec = GRUB_MD_SHA256;
+      break;
+    default:
+      return GRUB_ERR_BAD_ARGUMENT;
+    }
+
+  pcr_digest = grub_malloc (pcr_digest_len);
+  if (!pcr_digest)
+    {
+      fprintf (stderr, _("Failed to allocate PCR digest buffer.\n"));
+      return GRUB_ERR_OUT_OF_MEMORY;
+    }
+
+  pcr_concat_len = pcr_digest_len * args->tpm2_pcr_count;
+  pcr_concat = grub_malloc (pcr_concat_len);
+  if (!pcr_concat)
+    {
+      err = GRUB_ERR_OUT_OF_MEMORY;
+      fprintf (stderr, _("Failed to allocate PCR concatenation buffer.\n"));
+      goto exit1;
+    }
+
+  pcr_cursor = pcr_concat;
+  for (i = 0; i < args->tpm2_pcr_count; i++)
+    {
+      if (pcr_values.digests[i].size != pcr_digest_len)
+        {
+          fprintf (stderr,
+                   _("Bad PCR value size: expected %lu bytes but got %u 
bytes.\n"),
+                   pcr_digest_len, pcr_values.digests[i].size);
+          goto exit2;
+        }
+
+      grub_memcpy (pcr_cursor, pcr_values.digests[i].buffer, pcr_digest_len);
+      pcr_cursor += pcr_digest_len;
+    }
+
+  grub_crypto_hash (hash_spec, pcr_digest, pcr_concat, pcr_concat_len);
+
+  /* Start Trial Session */
+  nonce.size = TPM_SHA256_DIGEST_SIZE;
+  symmetric.algorithm = TPM_ALG_NULL;
+
+  rc = TPM2_StartAuthSession (TPM_RH_NULL, TPM_RH_NULL, 0, &nonce, &salt,
+                              TPM_SE_TRIAL, &symmetric, TPM_ALG_SHA256,
+                              &session, NULL, 0);
+  if (rc != TPM_RC_SUCCESS)
+    {
+      fprintf (stderr,
+               _("Failed to start trial policy session (TPM error: 0x%x).\n"),
+               rc);
+      err = GRUB_ERR_BAD_DEVICE;
+      goto exit2;
+    }
+
+  /* PCR Policy */
+  memcpy (pcr_digest_in.buffer, pcr_digest, TPM_SHA256_DIGEST_SIZE);
+
+  rc = TPM2_PolicyPCR (session, NULL, &pcr_digest_in, &pcr_sel, NULL);
+  if (rc != TPM_RC_SUCCESS)
+    {
+      fprintf (stderr, _("Failed to submit PCR policy (TPM error: 0x%x).\n"),
+               rc);
+      err = GRUB_ERR_BAD_DEVICE;
+      goto exit3;
+    }
+
+  /* Retrieve Policy Digest */
+  rc = TPM2_PolicyGetDigest (session, NULL, &policy_digest, NULL);
+  if (rc != TPM_RC_SUCCESS)
+    {
+      fprintf (stderr, _("Failed to get policy digest (TPM error: 0x%x).\n"),
+               rc);
+      err = GRUB_ERR_BAD_DEVICE;
+      goto exit3;
+    }
+
+  /* Epilogue */
+  *digest = policy_digest;
+  err = GRUB_ERR_NONE;
+
+exit3:
+  TPM2_FlushContext (session);
+
+exit2:
+  grub_free (pcr_concat);
+
+exit1:
+  grub_free (pcr_digest);
+
+  return err;
+}
+
+static grub_err_t
+grub_protect_tpm2_get_srk (struct grub_protect_args *args, TPM_HANDLE *srk)
+{
+  TPM_RC rc;
+  TPM2B_PUBLIC public;
+  TPMS_AUTH_COMMAND authCommand = { 0 };
+  TPM2B_SENSITIVE_CREATE inSensitive = { 0 };
+  TPM2B_PUBLIC inPublic = { 0 };
+  TPM2B_DATA outsideInfo = { 0 };
+  TPML_PCR_SELECTION creationPcr = { 0 };
+  TPM2B_PUBLIC outPublic = { 0 };
+  TPM2B_CREATION_DATA creationData = { 0 };
+  TPM2B_DIGEST creationHash = { 0 };
+  TPMT_TK_CREATION creationTicket = { 0 };
+  TPM2B_NAME srkName = { 0 };
+  TPM_HANDLE srkHandle;
+
+  /* Find SRK */
+  rc = TPM2_ReadPublic (args->tpm2_srk, NULL, &public);
+  if (rc == TPM_RC_SUCCESS)
+    {
+      if (args->tpm2_persist)
+        fprintf (stderr,
+                 _("Warning: --tpm2-persist was specified but the SRK already 
exists on the TPM. Continuing anyway...\n"));
+
+      *srk = TPM2_SRK_HANDLE;
+      return GRUB_ERR_NONE;
+    }
+
+  /* The handle exists but its public area could not be read. */
+  if ((rc & ~TPM_RC_N_MASK) != TPM_RC_HANDLE)
+    {
+      fprintf (stderr,
+               _("The SRK exists on the TPM but its public area cannot be read 
(TPM error: 0x%x).\n"),
+               rc);
+      return GRUB_ERR_BAD_DEVICE;
+    }
+
+  /* Create SRK */
+  authCommand.sessionHandle = TPM_RS_PW;
+  inPublic.publicArea.type = args->tpm2_asymmetric;
+  inPublic.publicArea.nameAlg  = TPM_ALG_SHA256;
+  inPublic.publicArea.objectAttributes.restricted = 1;
+  inPublic.publicArea.objectAttributes.userWithAuth = 1;
+  inPublic.publicArea.objectAttributes.decrypt = 1;
+  inPublic.publicArea.objectAttributes.fixedTPM = 1;
+  inPublic.publicArea.objectAttributes.fixedParent = 1;
+  inPublic.publicArea.objectAttributes.sensitiveDataOrigin = 1;
+  inPublic.publicArea.objectAttributes.noDA = 1;
+
+  switch (args->tpm2_asymmetric)
+    {
+    case TPM_ALG_RSA:
+      inPublic.publicArea.parameters.rsaDetail.symmetric.algorithm = 
TPM_ALG_AES;
+      inPublic.publicArea.parameters.rsaDetail.symmetric.keyBits.aes = 128;
+      inPublic.publicArea.parameters.rsaDetail.symmetric.mode.aes = 
TPM_ALG_CFB;
+      inPublic.publicArea.parameters.rsaDetail.scheme.scheme = TPM_ALG_NULL;
+      inPublic.publicArea.parameters.rsaDetail.keyBits = 2048;
+      inPublic.publicArea.parameters.rsaDetail.exponent = 0;
+      break;
+
+    case TPM_ALG_ECC:
+      inPublic.publicArea.parameters.eccDetail.symmetric.algorithm = 
TPM_ALG_AES;
+      inPublic.publicArea.parameters.eccDetail.symmetric.keyBits.aes = 128;
+      inPublic.publicArea.parameters.eccDetail.symmetric.mode.aes = 
TPM_ALG_CFB;
+      inPublic.publicArea.parameters.eccDetail.scheme.scheme = TPM_ALG_NULL;
+      inPublic.publicArea.parameters.eccDetail.curveID = TPM_ECC_NIST_P256;
+      inPublic.publicArea.parameters.eccDetail.kdf.scheme = TPM_ALG_NULL;
+      break;
+
+    default:
+      return GRUB_ERR_BAD_ARGUMENT;
+    }
+
+  rc = TPM2_CreatePrimary (TPM_RH_OWNER, &authCommand, &inSensitive, &inPublic,
+                           &outsideInfo, &creationPcr, &srkHandle, &outPublic,
+                           &creationData, &creationHash, &creationTicket,
+                           &srkName, NULL);
+  if (rc != TPM_RC_SUCCESS)
+    {
+      fprintf (stderr, _("Failed to create SRK (TPM error: 0x%x).\n"), rc);
+      return GRUB_ERR_BAD_DEVICE;
+    }
+
+  /* Persist SRK */
+  if (args->tpm2_persist)
+    {
+      rc = TPM2_EvictControl (TPM_RH_OWNER, srkHandle, args->tpm2_srk,
+                              &authCommand, NULL);
+      if (rc == TPM_RC_SUCCESS)
+        {
+          TPM2_FlushContext (srkHandle);
+          srkHandle = args->tpm2_srk;
+        }
+      else
+        fprintf (stderr,
+                 _("Warning: Failed to persist SRK (TPM error: 0x%x\n). 
Continuing anyway...\n"),
+                 rc);
+    }
+
+  /* Epilogue */
+  *srk = srkHandle;
+
+  return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_protect_tpm2_seal (TPM2B_DIGEST *policyDigest, TPM_HANDLE srk,
+                        grub_uint8_t *clearText, grub_size_t clearTextLength,
+                        TPM2_SEALED_KEY *sealed_key)
+{
+  TPM_RC rc;
+  TPMS_AUTH_COMMAND authCommand = { 0 };
+  TPM2B_SENSITIVE_CREATE inSensitive = { 0 };
+  TPM2B_PUBLIC inPublic  = { 0 };
+  TPM2B_DATA outsideInfo = { 0 };
+  TPML_PCR_SELECTION pcr_sel = { 0 };
+  TPM2B_PRIVATE outPrivate = { 0 };
+  TPM2B_PUBLIC outPublic = { 0 };
+
+  /* Seal Data */
+  authCommand.sessionHandle = TPM_RS_PW;
+
+  inSensitive.sensitive.data.size = clearTextLength;
+  memcpy(inSensitive.sensitive.data.buffer, clearText, clearTextLength);
+
+  inPublic.publicArea.type = TPM_ALG_KEYEDHASH;
+  inPublic.publicArea.nameAlg = TPM_ALG_SHA256;
+  inPublic.publicArea.parameters.keyedHashDetail.scheme.scheme = TPM_ALG_NULL;
+  inPublic.publicArea.authPolicy = *policyDigest;
+
+  rc = TPM2_Create (srk, &authCommand, &inSensitive, &inPublic, &outsideInfo,
+                    &pcr_sel, &outPrivate, &outPublic, NULL, NULL, NULL, NULL);
+  if (rc != TPM_RC_SUCCESS)
+    {
+      fprintf (stderr, _("Failed to seal key (TPM error: 0x%x).\n"), rc);
+      return GRUB_ERR_BAD_DEVICE;
+    }
+
+  /* Epilogue */
+  sealed_key->public = outPublic;
+  sealed_key->private = outPrivate;
+
+  return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_protect_tpm2_export_sealed_key (const char *filepath,
+                                     TPM2_SEALED_KEY *sealed_key)
+{
+  grub_err_t err;
+  struct grub_tpm2_buffer buf;
+
+  grub_tpm2_buffer_init (&buf);
+  grub_tpm2_mu_TPM2B_PUBLIC_Marshal (&buf, &sealed_key->public);
+  grub_tpm2_mu_TPM2B_Marshal (&buf, sealed_key->private.size,
+                              sealed_key->private.buffer);
+  if (buf.error)
+    return GRUB_ERR_BAD_ARGUMENT;
+
+  err = grub_protect_write_file (filepath, buf.data, buf.size);
+  if (err)
+    fprintf (stderr, _("Could not write sealed key file (Error: %u).\n"),
+             errno);
+
+  return err;
+}
+
+static grub_err_t
+grub_protect_tpm2_add (struct grub_protect_args *args)
+{
+  grub_err_t err;
+  grub_uint8_t *key;
+  grub_size_t key_size;
+  TPM_HANDLE srk;
+  TPM2B_DIGEST policy_digest;
+  TPM2_SEALED_KEY sealed_key;
+  char *grub_drive = NULL;
+
+  grub_protect_get_grub_drive_for_file (args->tpm2_outfile, &grub_drive);
+
+  err = grub_protect_tpm2_open_device (args->tpm2_device);
+  if (err)
+    return err;
+
+  err = grub_protect_read_file (args->tpm2_keyfile, (void **)&key, &key_size);
+  if (err)
+    goto exit1;
+
+  if (key_size > TPM_MAX_SYM_DATA)
+  {
+    fprintf (stderr,
+             _("Input key is too long, maximum allowed size is %u bytes.\n"),
+             TPM_MAX_SYM_DATA);
+    return GRUB_ERR_OUT_OF_RANGE;
+  }
+
+  err = grub_protect_tpm2_get_srk (args, &srk);
+  if (err)
+    goto exit2;
+
+  err = grub_protect_tpm2_get_policy_digest (args, &policy_digest);
+  if (err)
+    goto exit3;
+
+  err = grub_protect_tpm2_seal (&policy_digest, srk, key, key_size,
+                                &sealed_key);
+  if (err)
+    goto exit3;
+
+  err = grub_protect_tpm2_export_sealed_key (args->tpm2_outfile, &sealed_key);
+  if (err)
+    goto exit3;
+
+  if (grub_drive)
+    {
+      printf (_("GRUB drive for the sealed key file: %s\n"), grub_drive);
+      grub_free (grub_drive);
+    }
+  else
+    {
+      fprintf (stderr,
+               _("Warning: Could not determine GRUB drive for sealed key 
file.\n"));
+      err = GRUB_ERR_NONE;
+    }
+
+exit3:
+  TPM2_FlushContext (srk);
+
+exit2:
+  grub_free (key);
+
+exit1:
+  grub_protect_tpm2_close_device ();
+
+  return err;
+}
+
+static grub_err_t
+grub_protect_tpm2_remove (struct grub_protect_args *args)
+{
+  TPM_RC rc;
+  TPM2B_PUBLIC public;
+  TPMS_AUTH_COMMAND authCommand = { 0 };
+  grub_err_t err;
+
+  if (!args->tpm2_evict)
+    {
+      printf (_("--tpm2-evict not specified, nothing to do.\n"));
+      return GRUB_ERR_NONE;
+    }
+
+  err = grub_protect_tpm2_open_device (args->tpm2_device);
+  if (err)
+    return err;
+
+  /* Find SRK */
+  rc = TPM2_ReadPublic (args->tpm2_srk, NULL, &public);
+  if (rc != TPM_RC_SUCCESS)
+    {
+      fprintf (stderr, _("SRK with handle 0x%x not found.\n"), args->tpm2_srk);
+      err = GRUB_ERR_BAD_ARGUMENT;
+      goto exit1;
+    }
+
+  /* Evict SRK */
+  authCommand.sessionHandle = TPM_RS_PW;
+
+  rc = TPM2_EvictControl (TPM_RH_OWNER, args->tpm2_srk, args->tpm2_srk,
+                          &authCommand, NULL);
+  if (rc != TPM_RC_SUCCESS)
+    {
+      fprintf (stderr,
+               _("Failed to evict SRK with handle 0x%x (TPM Error: 0x%x).\n"),
+               args->tpm2_srk, rc);
+      err = GRUB_ERR_BAD_DEVICE;
+      goto exit2;
+    }
+
+  err = GRUB_ERR_NONE;
+
+exit2:
+  TPM2_FlushContext (args->tpm2_srk);
+
+exit1:
+  grub_protect_tpm2_close_device ();
+
+  return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_protect_tpm2_run (struct grub_protect_args *args)
+{
+  switch (args->action)
+    {
+    case GRUB_PROTECT_ACTION_ADD:
+      return grub_protect_tpm2_add (args);
+
+    case GRUB_PROTECT_ACTION_REMOVE:
+      return grub_protect_tpm2_remove (args);
+
+    default:
+      return GRUB_ERR_BAD_ARGUMENT;
+    }
+}
+
+static grub_err_t
+grub_protect_tpm2_args_verify (struct grub_protect_args *args)
+{
+  switch (args->action)
+    {
+    case GRUB_PROTECT_ACTION_ADD:
+      if (args->args & GRUB_PROTECT_ARG_TPM2_EVICT)
+        {
+          fprintf (stderr,
+                   _("--tpm2-evict is invalid when --action is 'add'.\n"));
+          return GRUB_ERR_BAD_ARGUMENT;
+        }
+
+      if (!args->tpm2_keyfile)
+        {
+          fprintf (stderr, _("--tpm2-keyfile must be specified.\n"));
+          return GRUB_ERR_BAD_ARGUMENT;
+        }
+
+      if (!args->tpm2_outfile)
+        {
+          fprintf (stderr, _("--tpm2-outfile must be specified.\n"));
+          return GRUB_ERR_BAD_ARGUMENT;
+        }
+
+      if (!args->tpm2_device)
+        args->tpm2_device = "/dev/tpm0";
+
+      if (!args->tpm2_pcr_count)
+        {
+          args->tpm2_pcrs[0] = 7;
+          args->tpm2_pcr_count = 1;
+        }
+
+      if (!args->tpm2_srk)
+        args->tpm2_srk = TPM2_SRK_HANDLE;
+
+      if (!args->tpm2_asymmetric)
+        args->tpm2_asymmetric = TPM_ALG_RSA;
+
+      if (!args->tpm2_bank)
+        args->tpm2_bank = TPM_ALG_SHA256;
+
+      break;
+
+    case GRUB_PROTECT_ACTION_REMOVE:
+      if (args->args & GRUB_PROTECT_ARG_TPM2_ASYMMETRIC)
+        {
+          fprintf (stderr,
+                   _("--tpm2-asymmetric is invalid when --action is 
'remove'.\n"));
+          return GRUB_ERR_BAD_ARGUMENT;
+        }
+
+      if (args->args & GRUB_PROTECT_ARG_TPM2_BANK)
+        {
+          fprintf (stderr,
+                   _("--tpm2-bank is invalid when --action is 'remove'.\n"));
+          return GRUB_ERR_BAD_ARGUMENT;
+        }
+
+      if (args->args & GRUB_PROTECT_ARG_TPM2_KEYFILE)
+        {
+          fprintf (stderr,
+                   _("--tpm2-keyfile is invalid when --action is 
'remove'.\n"));
+          return GRUB_ERR_BAD_ARGUMENT;
+        }
+
+      if (args->args & GRUB_PROTECT_ARG_TPM2_OUTFILE)
+        {
+          fprintf (stderr,
+                   _("--tpm2-outfile is invalid when --action is 
'remove'.\n"));
+          return GRUB_ERR_BAD_ARGUMENT;
+        }
+
+      if (args->args & GRUB_PROTECT_ARG_TPM2_PCRS)
+        {
+          fprintf (stderr,
+                   _("--tpm2-pcrs is invalid when --action is 'remove'.\n"));
+          return GRUB_ERR_BAD_ARGUMENT;
+        }
+
+      if (args->args & GRUB_PROTECT_ARG_TPM2_PERSIST)
+        {
+          fprintf (stderr,
+                   _("--tpm2-persist is invalid when --action is 
'remove'.\n"));
+          return GRUB_ERR_BAD_ARGUMENT;
+        }
+
+      if (!args->tpm2_device)
+        args->tpm2_device = "/dev/tpm0";
+
+      if (!args->tpm2_srk)
+        args->tpm2_srk = TPM2_SRK_HANDLE;
+
+      break;
+
+    default:
+      fprintf (stderr,
+               _("The TPM2 key protector only supports the following actions: 
add, remove.\n"));
+      return GRUB_ERR_BAD_ARGUMENT;
+    }
+
+  return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_protector_args_kvp_parse (char *kvp, const char **key, char **value)
+{
+  char divider;
+  char *separator;
+  grub_size_t len;
+
+  if (!kvp)
+    return GRUB_ERR_BAD_ARGUMENT;
+
+  len = grub_strlen (kvp);
+  if (!len || len < 2)
+    return GRUB_ERR_BAD_ARGUMENT;
+
+  if (kvp[0] == '-' && kvp[1] != '-')
+    divider = ' ';
+  else if (kvp[0] == '-' && kvp[1] == '-')
+    divider = '=';
+  else
+    return GRUB_ERR_BAD_ARGUMENT;
+
+  separator = grub_strchr (kvp, divider);
+  if (!separator)
+    goto exit;
+
+  *separator = '\0';
+  separator += 1;
+
+  if (separator - kvp >= len)
+  {
+    separator = NULL;
+    goto exit;
+  }
+
+exit:
+  *key = kvp;
+  *value = separator;
+
+  return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_protect_args_parse (int argc, char *argv[],
+                         struct grub_protect_args *args)
+{
+  grub_err_t err;
+  char *current_arg;
+  const char *key;
+  char *value;
+  int i;
+
+  for (i = 1; i < argc; i++)
+    {
+      current_arg = argv[i];
+
+      err = grub_protector_args_kvp_parse (current_arg, &key, &value);
+      if (err)
+        return err;
+
+      if (grub_strcmp (key, "--action") == 0 ||
+          grub_strcmp (key, "-a") == 0)
+        {
+          if (args->args & GRUB_PROTECT_ARG_ACTION)
+            {
+              fprintf (stderr,
+                       _("Argument %s was already specified.\n"), key);
+              return GRUB_ERR_BAD_ARGUMENT;
+            }
+
+          if (!value)
+            {
+              fprintf (stderr, _("Argument %s requires a value.\n"), key);
+              return GRUB_ERR_BAD_ARGUMENT;
+            }
+
+          if (grub_strcmp (value, "add") == 0)
+            args->action = GRUB_PROTECT_ACTION_ADD;
+          else if (grub_strcmp (value, "remove") == 0)
+            args->action = GRUB_PROTECT_ACTION_REMOVE;
+          else
+            {
+              fprintf (stderr, _("'%s' is not a valid action.\n"), value);
+              return GRUB_ERR_BAD_ARGUMENT;
+            }
+
+          args->args |= GRUB_PROTECT_ARG_ACTION;
+        }
+      else if (grub_strcmp (key, "--protector") == 0 ||
+               grub_strcmp (key, "-p") == 0)
+        {
+          if (args->args & GRUB_PROTECT_ARG_PROTECTOR)
+            {
+              fprintf (stderr, _("Argument %s was already specified.\n"), key);
+              return GRUB_ERR_BAD_ARGUMENT;
+            }
+
+          if (!value)
+            {
+              fprintf (stderr, _("Argument %s requires a value.\n"), key);
+              return GRUB_ERR_BAD_ARGUMENT;
+            }
+
+          if (grub_strcmp (value, "tpm2") == 0)
+            args->protector = GRUB_PROTECT_TYPE_TPM2;
+          else
+            {
+              fprintf (stderr, _("'%s' is not a valid protector.\n"), value);
+              return GRUB_ERR_BAD_ARGUMENT;
+            }
+
+          args->args |= GRUB_PROTECT_ARG_PROTECTOR;
+        }
+      else if (grub_strcmp (key, "--tpm2-device") == 0)
+        {
+          if (args->args & GRUB_PROTECT_ARG_TPM2_DEVICE)
+            {
+              fprintf (stderr, _("Argument %s was already specified.\n"), key);
+              return GRUB_ERR_BAD_ARGUMENT;
+            }
+
+          if (!value)
+            {
+              fprintf (stderr, _("Argument %s requires a value.\n"), key);
+              return GRUB_ERR_BAD_ARGUMENT;
+            }
+
+          args->tpm2_device = value;
+          args->args |= GRUB_PROTECT_ARG_TPM2_DEVICE;
+        }
+      else if (grub_strcmp (key, "--tpm2-pcrs") == 0)
+        {
+          if (args->args & GRUB_PROTECT_ARG_TPM2_PCRS)
+            {
+              fprintf (stderr, _("Argument %s was already specified.\n"), key);
+              return GRUB_ERR_BAD_ARGUMENT;
+            }
+
+          if (!value)
+            {
+              fprintf (stderr, _("Argument %s requires a value.\n"), key);
+              return GRUB_ERR_BAD_ARGUMENT;
+            }
+
+          grub_size_t len = grub_strlen (value);
+          grub_size_t dist;
+
+          long pcr;
+          char *next_pcr;
+          char *current_pcr = value;
+          grub_uint8_t pcr_u8;
+          grub_uint8_t j;
+          grub_uint8_t k;
+
+          for (j = 0;; j++)
+            {
+              next_pcr = grub_strchr (current_pcr, ',');
+              if (next_pcr)
+                *next_pcr = '\0';
+
+              grub_errno = GRUB_ERR_NONE;
+              pcr = grub_strtoul (current_pcr, NULL, 0);
+              if (grub_errno != GRUB_ERR_NONE)
+                {
+                  fprintf (stderr, _("'%s' is not a valid PCR number.\n"),
+                           current_pcr);
+                  return grub_errno;
+                }
+
+              if (pcr > TPM_MAX_PCRS)
+                {
+                  fprintf (stderr,
+                           _("%lu larger than the maximum number of PCRs.\n"),
+                           pcr);
+                  return GRUB_ERR_OUT_OF_RANGE;
+                }
+
+              pcr_u8 = (grub_uint8_t)pcr;
+
+              for (k = 0; k < args->tpm2_pcr_count; k++)
+              {
+                if (args->tpm2_pcrs[k] == pcr_u8)
+                  {
+                    fprintf (stderr, _("PCR %u was already specified.\n"),
+                             pcr_u8);
+                    return GRUB_ERR_BAD_ARGUMENT;
+                  }
+              }
+
+              args->tpm2_pcrs[j] = pcr_u8;
+              args->tpm2_pcr_count++;
+
+              if (!next_pcr)
+                break;
+
+              current_pcr = next_pcr + 1;
+
+              dist = (current_pcr - value);
+              if (dist >= len)
+                break;
+            }
+
+          args->args |= GRUB_PROTECT_ARG_TPM2_PCRS;
+        }
+      else if (grub_strcmp (key, "--tpm2-srk") == 0)
+        {
+          if (args->args & GRUB_PROTECT_ARG_TPM2_SRK)
+            {
+              fprintf (stderr, _("Argument %s was already specified.\n"), key);
+              return GRUB_ERR_BAD_ARGUMENT;
+            }
+
+          if (!value)
+            {
+              fprintf (stderr, _("Argument %s requires a value.\n"), key);
+              return GRUB_ERR_BAD_ARGUMENT;
+            }
+
+          long srk;
+
+          grub_errno = GRUB_ERR_NONE;
+          srk = grub_strtoul (value, NULL, 0);
+          if (grub_errno != GRUB_ERR_NONE)
+            {
+              fprintf (stderr, _("'%s' is not a valid SRK handle.\n"), value);
+              return grub_errno;
+            }
+
+          if (srk > GRUB_UINT_MAX)
+            {
+              fprintf (stderr,
+                       _("%lu is too large to be a valid SRK handle.\n"), srk);
+              return GRUB_ERR_OUT_OF_RANGE;
+            }
+
+          args->tpm2_srk = (TPM_HANDLE)srk;
+          args->args |= GRUB_PROTECT_ARG_TPM2_SRK;
+        }
+      else if (grub_strcmp (key, "--tpm2-asymmetric") == 0)
+        {
+          if (args->args & GRUB_PROTECT_ARG_TPM2_ASYMMETRIC)
+            {
+              fprintf (stderr, _("Argument %s was already specified.\n"), key);
+              return GRUB_ERR_BAD_ARGUMENT;
+            }
+
+          if (!value)
+            {
+              fprintf (stderr, _("Argument %s requires a value.\n"), key);
+              return GRUB_ERR_BAD_ARGUMENT;
+            }
+
+          if (grub_strcasecmp (value, "ECC") == 0)
+            args->tpm2_asymmetric = TPM_ALG_ECC;
+          else if (grub_strcasecmp (value, "RSA") == 0)
+            args->tpm2_asymmetric = TPM_ALG_RSA;
+          else
+            {
+              fprintf (stderr, _("'%s' is not a valid asymmetric 
algorithm.\n"),
+                       value);
+              return GRUB_ERR_BAD_ARGUMENT;
+            }
+
+          args->args |= GRUB_PROTECT_ARG_TPM2_ASYMMETRIC;
+        }
+      else if (grub_strcmp (key, "--tpm2-bank") == 0)
+        {
+          if (args->args & GRUB_PROTECT_ARG_TPM2_BANK)
+            {
+              fprintf (stderr, _("Argument %s was already specified.\n"), key);
+              return GRUB_ERR_BAD_ARGUMENT;
+            }
+
+          if (!value)
+            {
+              fprintf (stderr, _("Argument %s requires a value.\n"), key);
+              return GRUB_ERR_BAD_ARGUMENT;
+            }
+
+          if (grub_strcasecmp (value, "SHA1") == 0)
+            args->tpm2_bank = TPM_ALG_SHA1;
+          else if (grub_strcasecmp (value, "SHA256") == 0)
+            args->tpm2_bank = TPM_ALG_SHA256;
+          else
+            {
+              fprintf (stderr, _("'%s' is not a valid PCR bank.\n"), value);
+              return GRUB_ERR_BAD_ARGUMENT;
+            }
+
+          args->args |= GRUB_PROTECT_ARG_TPM2_BANK;
+        }
+      else if (grub_strcmp (key, "--tpm2-keyfile") == 0)
+        {
+          if (args->args & GRUB_PROTECT_ARG_TPM2_KEYFILE)
+            {
+              fprintf (stderr, _("Argument %s was already specified.\n"), key);
+              return GRUB_ERR_BAD_ARGUMENT;
+            }
+
+          if (!value)
+            {
+              fprintf (stderr, _("Argument %s requires a value.\n"), key);
+              return GRUB_ERR_BAD_ARGUMENT;
+            }
+
+         args->tpm2_keyfile = value;
+          args->args |= GRUB_PROTECT_ARG_TPM2_KEYFILE;
+        }
+      else if (grub_strcmp (key, "--tpm2-outfile") == 0)
+        {
+          if (args->args & GRUB_PROTECT_ARG_TPM2_OUTFILE)
+            {
+              fprintf (stderr, _("Argument %s was already specified.\n"), key);
+              return GRUB_ERR_BAD_ARGUMENT;
+            }
+
+          if (!value)
+            {
+              fprintf (stderr, _("Argument %s requires a value.\n"), key);
+              return GRUB_ERR_BAD_ARGUMENT;
+            }
+
+          args->tpm2_outfile = value;
+          args->args |= GRUB_PROTECT_ARG_TPM2_OUTFILE;
+        }
+      else if (grub_strcmp (key, "--tpm2-persist") == 0)
+        {
+          if (args->args & GRUB_PROTECT_ARG_TPM2_PERSIST)
+            {
+              fprintf (stderr, _("Argument %s was already specified.\n"), key);
+              return GRUB_ERR_BAD_ARGUMENT;
+            }
+
+          if (value)
+            {
+              fprintf (stderr, _("Argument %s does not accept a value.\n"),
+                       key);
+              return GRUB_ERR_BAD_ARGUMENT;
+            }
+
+          args->tpm2_persist = 1;
+          args->args |= GRUB_PROTECT_ARG_TPM2_PERSIST;
+        }
+      else if (grub_strcmp (key, "--tpm2-evict") == 0)
+        {
+          if (args->args & GRUB_PROTECT_ARG_TPM2_EVICT)
+            {
+              fprintf (stderr, _("Argument %s was already specified.\n"), key);
+              return GRUB_ERR_BAD_ARGUMENT;
+            }
+
+          if (value)
+            {
+              fprintf (stderr, _("Argument %s does not accept a value.\n"),
+                       key);
+              return GRUB_ERR_BAD_ARGUMENT;
+            }
+
+          args->tpm2_evict = 1;
+          args->args |= GRUB_PROTECT_ARG_TPM2_EVICT;
+        }
+        else
+          {
+            fprintf (stderr, _("'%s' is not a valid argument.\n"), key);
+            return GRUB_ERR_BAD_ARGUMENT;
+          }
+    }
+
+  return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_protect_args_verify (struct grub_protect_args *args)
+{
+  if (args->action == GRUB_PROTECT_ACTION_ERROR)
+    {
+      fprintf (stderr, "--action is mandatory.\n");
+      return GRUB_ERR_BAD_ARGUMENT;
+    }
+
+  /* At the moment, the only configurable key protector is the TPM2 one, so it
+   * is the only keu protector supported by this tool. */
+  if (args->protector != GRUB_PROTECT_TYPE_TPM2)
+    {
+      fprintf (stderr,
+               _("--protector is mandatory and only 'tpm2' is currently 
supported.\n"));
+      return GRUB_ERR_BAD_ARGUMENT;
+    }
+
+  switch (args->protector)
+    {
+    case GRUB_PROTECT_TYPE_TPM2:
+      return grub_protect_tpm2_args_verify (args);
+    default:
+      return GRUB_ERR_BAD_ARGUMENT;
+    }
+
+  return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_protect_dispatch (struct grub_protect_args *args)
+{
+  switch (args->protector)
+    {
+    case GRUB_PROTECT_TYPE_TPM2:
+      return grub_protect_tpm2_run (args);
+    default:
+      return GRUB_ERR_BAD_ARGUMENT;
+    }
+}
+
+static void
+grub_protect_init (int *argc, char **argv[])
+{
+  grub_util_host_init (argc, argv);
+
+  grub_util_biosdisk_init (NULL);
+
+  grub_init_all ();
+  grub_gcry_init_all ();
+
+  grub_lvm_fini ();
+  grub_mdraid09_fini ();
+  grub_mdraid1x_fini ();
+  grub_diskfilter_fini ();
+  grub_diskfilter_init ();
+  grub_mdraid09_init ();
+  grub_mdraid1x_init ();
+  grub_lvm_init ();
+}
+
+static void
+grub_protect_fini (void)
+{
+  grub_gcry_fini_all ();
+  grub_fini_all ();
+  grub_util_biosdisk_fini ();
+}
+
+int
+main (int argc, char *argv[])
+{
+  grub_err_t err;
+  struct grub_protect_args args = { 0 };
+
+  grub_protect_init (&argc, &argv);
+
+  err = grub_protect_args_parse (argc, argv, &args);
+  if (err)
+    goto exit;
+
+  err = grub_protect_args_verify (&args);
+  if (err)
+    goto exit;
+
+  err = grub_protect_dispatch (&args);
+  if (err)
+    goto exit;
+
+exit:
+  grub_protect_fini ();
+
+  return err;
+}
-- 
1.8.3.1




reply via email to

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