grub-devel
[Top][All Lists]
Advanced

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

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


From: Glenn Washburn
Subject: Re: [PATCH 5/5] util/grub-protect: Add new tool
Date: Mon, 24 Jan 2022 23:45:55 -0600

On Mon, 24 Jan 2022 06:12:18 -0800
Hernan Gatta <hegatta@linux.microsoft.com> wrote:

> 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.

I think you mean '-k' instead of '-p' here.

> 
> 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

Why not have a syntax that is similar to whats given to cryptomount?
(eg. $ sudo grub-protect --action=add
--protector=tpm2:keyfile=/boot/efi/boot/grub2/sealed_key ) This would
allow you to re-use the parsing code from patch #3. Yes, its less
UNIXy, but I think could be more intuitive and cuts down on code size.
I'm not completely wedded to this idea either.

> 
> Then, in the boot script (wrapped for display):
> 
> cryptomount -u b20f95d0834842bc9197bd78b36732f8
> -p tpm2:keyfile=(hd0,gpt1)/boot/grub2/sealed_key

Also, -k here.

> 
> 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)
> +{

I'm wondering if it wouldn't be a good idea to merge this function with
grub_tpm2_protector_check_args from patch #3. This is probably only
manageable if the protector argument looks like the one from grub as
well, so they can share error messages.

> +  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";

Seems like this...

> +
> +      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;

and maybe this, can be done outside the switch since they are common to
both cases.

> +
> +      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)

This might be confusing because its -p here but -k to cryptomount.

> +        {
> +          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;
> +}

It would be nice to take arguments --help and -h and spit out something
useful.

Glenn




reply via email to

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