On Fri, Apr 12, 2024 at 04:52:02PM -0400, Stefan Berger wrote:
> 
> 
> On 4/12/24 04:39, Gary Lin via Grub-devel wrote:
> > From: Hernan Gatta <hega...@linux.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 LUKS 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
> > has to ensure the cryptomount command is included in GRUB's boot script
> > and that it carries the requisite key protector (-P) parameter.
> > 
> > Sample usage:
> > 
> > $ dd if=/dev/urandom of=luks-key bs=1 count=32
> > $ sudo cryptsetup luksAddKey /dev/sdb1 luks-key --pbkdf=pbkdf2 --hash=sha512
> > 
> > To seal the key with TPM 2.0 Key File (recommended):
> > 
> > $ sudo grub-protect --action=add \
> >                      --protector=tpm2 \
> >                 --tpm2-pcrs=0,2,4,7,9 \
> >                      --tpm2key \
> >                      --tpm2-keyfile=luks-key \
> >                      --tpm2-outfile=/boot/efi/boot/grub2/sealed.tpm
> > 
> > Or, to seal the key with the raw sealed key:
> > 
> > $ sudo grub-protect --action=add \
> >                      --protector=tpm2 \
> >                 --tpm2-pcrs=0,2,4,7,9 \
> >                      --tpm2-keyfile=luks-key \
> >                      --tpm2-outfile=/boot/efi/boot/grub2/sealed.key
> > 
> > Then, in the boot script, for TPM 2.0 Key File:
> > 
> > tpm2_key_protector_init --tpm2key=(hd0,gpt1)/boot/grub2/sealed.tpm
> > cryptomount -u <SDB1_UUID> -P tpm2
> > 
> > Or, for the raw sealed key:
> > 
> > tpm2_key_protector_init --keyfile=(hd0,gpt1)/boot/grub2/sealed.key 
> > --pcrs=0,2,4,7,9
> > cryptomount -u <SDB1_UUID> -P tpm2
> > 
> > The benefit of using TPM 2.0 Key File is that the PCR set is already
> > written in the key file, so there is no need to specify PCRs when
> > invoking tpm2_key_protector_init.
> > 
> > Signed-off-by: Hernan Gatta <hega...@linux.microsoft.com>
> > Signed-off-by: Gary Lin <g...@suse.com>
> > ---
> >   .gitignore          |    2 +
> >   Makefile.util.def   |   22 +
> >   configure.ac        |   30 +
> >   util/grub-protect.c | 1396 +++++++++++++++++++++++++++++++++++++++++++
> >   4 files changed, 1450 insertions(+)
> >   create mode 100644 util/grub-protect.c
> > 
> > diff --git a/.gitignore b/.gitignore
> > index 4d0dfb700..d7b7c22d6 100644
> > --- a/.gitignore
> > +++ b/.gitignore
> > @@ -169,6 +169,8 @@ widthspec.bin
> >   /grub-ofpathname.exe
> >   /grub-probe
> >   /grub-probe.exe
> > +/grub-protect
> > +/grub-protect.exe
> >   /grub-reboot
> >   /grub-render-label
> >   /grub-render-label.exe
> > diff --git a/Makefile.util.def b/Makefile.util.def
> > index 19ad5a96f..a0a3e2cd5 100644
> > --- a/Makefile.util.def
> > +++ b/Makefile.util.def
> > @@ -207,6 +207,28 @@ program = {
> >     ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
> >   };
> > +program = {
> > +  name = grub-protect;
> > +
> > +  common = grub-core/osdep/init.c;
> > +  common = grub-core/tpm2/args.c;
> > +  common = grub-core/tpm2/buffer.c;
> > +  common = grub-core/tpm2/mu.c;
> > +  common = grub-core/tpm2/tpm2.c;
> > +  common = grub-core/tpm2/tpm2key_asn1_tab.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 = '$(LIBTASN1)';
> > +  ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) 
> > $(LIBGEOM)';
> > +
> > +  condition = COND_GRUB_PROTECT;
> > +};
> > +
> >   program = {
> >     name = grub-mkrelpath;
> >     mansection = 1;
> > diff --git a/configure.ac b/configure.ac
> > index 84a202c6e..3a07ab570 100644
> > --- a/configure.ac
> > +++ b/configure.ac
> > @@ -76,6 +76,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])
> > @@ -2057,6 +2058,29 @@ fi
> >   AC_SUBST([LIBZFS])
> >   AC_SUBST([LIBNVPAIR])
> > +AC_ARG_ENABLE([grub-protect],
> > +         [AS_HELP_STRING([--enable-grub-protect],
> > +                             [build and install the `grub-protect' utility 
> > (default=guessed)])])
> > +if test x"$enable_grub_protect" = xno ; then
> > +  grub_protect_excuse="explicitly disabled"
> > +fi
> > +
> > +LIBTASN1=
> > +if test x"$grub_protect_excuse" = x ; then
> > +  AC_CHECK_LIB([tasn1], [asn1_write_value], [LIBTASN1="-ltasn1"], 
> > [grub_protect_excuse="need libtasn1 library"])
> > +fi
> > +AC_SUBST([LIBTASN1])
> > +
> > +if test x"$enable_grub_protect" = xyes && test x"$grub_protect_excuse" != 
> > x ; then
> > +  AC_MSG_ERROR([grub-protect was explicitly requested but can't be 
> > compiled ($grub_protect_excuse)])
> > +fi
> > +if test x"$grub_protect_excuse" = x ; then
> > +enable_grub_protect=yes
> > +else
> > +enable_grub_protect=no
> > +fi
> > +AC_SUBST([enable_grub_protect])
> > +
> >   LIBS=""
> >   AC_SUBST([FONT_SOURCE])
> > @@ -2173,6 +2197,7 @@ AM_CONDITIONAL([COND_GRUB_EMU_SDL], [test 
> > x$enable_grub_emu_sdl = xyes])
> >   AM_CONDITIONAL([COND_GRUB_EMU_PCI], [test x$enable_grub_emu_pci = xyes])
> >   AM_CONDITIONAL([COND_GRUB_MKFONT], [test x$enable_grub_mkfont = xyes])
> >   AM_CONDITIONAL([COND_GRUB_MOUNT], [test x$enable_grub_mount = xyes])
> > +AM_CONDITIONAL([COND_GRUB_PROTECT], [test x$enable_grub_protect = xyes])
> >   AM_CONDITIONAL([COND_HAVE_FONT_SOURCE], [test x$FONT_SOURCE != x])
> >   if test x$FONT_SOURCE != x ; then
> >      HAVE_FONT_SOURCE=1
> > @@ -2300,6 +2325,11 @@ echo grub-mount: Yes
> >   else
> >   echo grub-mount: No "($grub_mount_excuse)"
> >   fi
> > +if [ x"$grub_protect_excuse" = x ]; then
> > +echo grub-protect: Yes
> > +else
> > +echo grub-protect: No "($grub_protect_excuse)"
> > +fi
> >   if [ x"$starfield_excuse" = x ]; then
> >   echo starfield theme: Yes
> >   echo With DejaVuSans font from $DJVU_FONT_SOURCE
> > diff --git a/util/grub-protect.c b/util/grub-protect.c
> > new file mode 100644
> > index 000000000..7e2f80455
> > --- /dev/null
> > +++ b/util/grub-protect.c
> > @@ -0,0 +1,1396 @@
> > +/*
> > + *  GRUB  --  GRand Unified Bootloader
> > + *  Copyright (C) 2022 Microsoft Corporation
> > + *  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 <config.h>
> > +
> > +#include <errno.h>
> > +#include <fcntl.h>
> > +#include <libtasn1.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/internal/args.h>
> > +#include <grub/tpm2/mu.h>
> > +#include <grub/tpm2/tcg2.h>
> > +#include <grub/tpm2/tpm2.h>
> > +#include <grub/util/misc.h>
> > +
> > +#pragma GCC diagnostic ignored "-Wmissing-prototypes"
> > +#pragma GCC diagnostic ignored "-Wmissing-declarations"
> > +#include <argp.h>
> > +#pragma GCC diagnostic error "-Wmissing-prototypes"
> > +#pragma GCC diagnostic error "-Wmissing-declarations"
> > +
> > +#include "progname.h"
> > +
> > +/* Unprintable option keys for argp */
> > +typedef enum grub_protect_opt
> > +{
> > +  /* General */
> > +  GRUB_PROTECT_OPT_ACTION      = 'a',
> > +  GRUB_PROTECT_OPT_PROTECTOR   = 'p',
> > +  /* TPM2 */
> > +  GRUB_PROTECT_OPT_TPM2_DEVICE = 0x100,
> > +  GRUB_PROTECT_OPT_TPM2_PCRS,
> > +  GRUB_PROTECT_OPT_TPM2_ASYMMETRIC,
> > +  GRUB_PROTECT_OPT_TPM2_BANK,
> > +  GRUB_PROTECT_OPT_TPM2_SRK,
> > +  GRUB_PROTECT_OPT_TPM2_KEYFILE,
> > +  GRUB_PROTECT_OPT_TPM2_OUTFILE,
> > +  GRUB_PROTECT_OPT_TPM2_EVICT,
> > +  GRUB_PROTECT_OPT_TPM2_TPM2KEY
> > +} grub_protect_opt;
> > +
> > +/* Option flags to keep track of specified arguments */
> > +typedef enum grub_protect_arg
> > +{
> > +  /* General */
> > +  GRUB_PROTECT_ARG_ACTION          = 1 << 0,
> > +  GRUB_PROTECT_ARG_PROTECTOR       = 1 << 1,
> > +  /* TPM2 */
> > +  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_EVICT      = 1 << 9,
> > +  GRUB_PROTECT_ARG_TPM2_TPM2KEY    = 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;
> > +  grub_srk_type_t srk_type;
> > +  TPM_ALG_ID tpm2_bank;
> > +  TPM_HANDLE tpm2_srk;
> > +  const char *tpm2_keyfile;
> > +  const char *tpm2_outfile;
> > +  int tpm2_evict;
> > +  int tpm2_tpm2key;
> > +};
> > +
> > +static struct argp_option grub_protect_options[] =
> > +  {
> > +    /* Top-level options */
> > +   {
> > +      .name  = "action",
> > +      .key   = 'a',
> > +      .arg   = "add|remove",
> > +      .flags = 0,
> > +      .doc   =
> > +   N_("Add or remove a key protector to or from a key."),
> > +      .group = 0
> > +    },
> > +    {
> > +      .name  = "protector",
> > +      .key   = 'p',
> > +      .arg   = "tpm2",
> > +      .flags = 0,
> > +      .doc   =
> > +   N_("Key protector to use (only tpm2 is currently supported)."),
> > +      .group = 0
> > +    },
> > +    /* TPM2 key protector options */
> > +    {
> > +      .name = "tpm2-device",
> > +      .key   = GRUB_PROTECT_OPT_TPM2_DEVICE,
> > +      .arg   = "FILE",
> > +      .flags = 0,
> > +      .doc   =
> > +   N_("Path to the TPM2 device (default is /dev/tpm0)."),
> > +      .group = 0
> > +    },
> > +    {
> > +      .name = "tpm2-pcrs",
> > +      .key   = GRUB_PROTECT_OPT_TPM2_PCRS,
> > +      .arg   = "0[,1]...",
> > +      .flags = 0,
> > +      .doc   =
> > +   N_("Comma-separated list of PCRs used to authorize key release "
> > +      "(e.g., '7,11', default is 7."),
> > +      .group = 0
> > +    },
> > +    {
> > +      .name = "tpm2-bank",
> > +      .key  = GRUB_PROTECT_OPT_TPM2_BANK,
> > +      .arg   = "ALG",
> > +      .flags = 0,
> > +      .doc   =
> > +   N_("Bank of PCRs used to authorize key release: "
> > +      "SHA1, SHA256 (default), or SHA512."),
> > +      .group = 0
> > +    },
> > +    {
> > +      .name = "tpm2-keyfile",
> > +      .key   = GRUB_PROTECT_OPT_TPM2_KEYFILE,
> > +      .arg   = "FILE",
> > +      .flags = 0,
> > +      .doc   =
> > +   N_("Path to a file that contains the cleartext key to protect."),
> > +      .group = 0
> > +    },
> > +    {
> > +      .name = "tpm2-outfile",
> > +      .key   = GRUB_PROTECT_OPT_TPM2_OUTFILE,
> > +      .arg   = "FILE",
> > +      .flags = 0,
> > +      .doc   =
> > +   N_("Path to the file that will contain the key after sealing (must be "
> > +      "accessible to GRUB during boot)."),
> > +      .group = 0
> > +    },
> > +    {
> > +      .name = "tpm2-srk",
> > +      .key   = GRUB_PROTECT_OPT_TPM2_SRK,
> > +      .arg   = "NUM",
> > +      .flags = 0,
> > +      .doc   =
> > +   N_("The SRK handle if the SRK is to be made persistent."),
> > +      .group = 0
> > +    },
> > +    {
> > +      .name = "tpm2-asymmetric",
> > +      .key   = GRUB_PROTECT_OPT_TPM2_ASYMMETRIC,
> > +      .arg   = "TYPE",
> > +      .flags = 0,
> > +      .doc   =
> > +   N_("The type of SRK: RSA (RSA2048), RSA3072, RSA4096, "
> > +      "ECC (ECC_NIST_P256), ECC_NIST_P384, ECC_NIST_P521, "
> > +      "ECC_BN_P256, ECC_BN_P638, and ECC_SM2_P256. "
> > +      "(default is ECC_NIST_P256)"),
> > +      .group = 0
> > +    },
> > +    {
> > +      .name = "tpm2-evict",
> > +      .key   = GRUB_PROTECT_OPT_TPM2_EVICT,
> > +      .arg   = NULL,
> > +      .flags = 0,
> > +      .doc   =
> > +   N_("Evict a previously persisted SRK from the TPM, if any."),
> > +      .group = 0
> > +    },
> > +    {
> > +      .name = "tpm2key",
> > +      .key   = GRUB_PROTECT_OPT_TPM2_TPM2KEY,
> > +      .arg   = NULL,
> > +      .flags = 0,
> > +      .doc   =
> > +   N_("Use TPM 2.0 Key File format instead of the raw format."),
> > +      .group = 0
> > +    },
> > +    /* End of list */
> > +    { 0, 0, 0, 0, 0, 0 }
> > +  };
> > +
> > +static int grub_protector_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 == NULL)
> > +    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 <= 0)
> > +    {
> > +       err = GRUB_ERR_FILE_READ_ERROR;
> > +       goto exit1;
> > +    }
> > +
> > +  rewind (f);
> > +
> > +  buf = grub_malloc (len);
> > +  if (buf == NULL)
> > +    {
> > +       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 == NULL)
> > +    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;
> > +}
> > +
> > +grub_err_t
> > +grub_tcg2_get_max_output_size (grub_size_t *size)
> > +{
> > +  if (size == NULL)
> > +    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 (grub_protector_tpm2_fd, input, input_size) != input_size)
> > +    return GRUB_ERR_BAD_DEVICE;
> > +
> > +  if (read (grub_protector_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 (grub_protector_tpm2_fd != -1)
> > +    return GRUB_ERR_NONE;
> > +
> > +  grub_protector_tpm2_fd = open (dev_node, O_RDWR);
> > +  if (grub_protector_tpm2_fd == -1)
> > +    {
> > +      fprintf (stderr, _("Could not open TPM device (%s).\n"), strerror 
> > (errno));
> > +      return GRUB_ERR_FILE_NOT_FOUND;
> > +    }
> > +
> > +  return GRUB_ERR_NONE;
> > +}
> > +
> > +static grub_err_t
> > +grub_protect_tpm2_close_device (void)
> > +{
> > +  int err;
> > +
> > +  if (grub_protector_tpm2_fd == -1)
> > +    return GRUB_ERR_NONE;
> > +
> > +  err = close (grub_protector_tpm2_fd);
> > +  if (err != GRUB_ERR_NONE)
> > +  {
> > +    fprintf (stderr, _("Could not close TPM device (Error: %u).\n"), 
> > errno);
> > +    return GRUB_ERR_IO;
> > +  }
> > +
> > +  grub_protector_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++)
> > +    TPMS_PCR_SELECTION_SelectPCR (&pcr_sel.pcrSelections[0], 
> > args->tpm2_pcrs[i]);
> > +
> > +  rc = TPM2_PCR_Read (NULL, &pcr_sel, NULL, &pcr_sel_out, &pcr_values, 
> > NULL);
> > +  if (rc != TPM_RC_SUCCESS)
> > +    {
> > +      fprintf (stderr, _("Failed to read PCRs (TPM2_PCR_Read: 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;
> > +    case TPM_ALG_SHA512:
> > +      pcr_digest_len = TPM_SHA512_DIGEST_SIZE;
> > +      hash_spec = GRUB_MD_SHA512;
> > +      break;
> > +    /* Although SHA384 can be parsed by grub_tpm2_protector_parse_bank(),
> > +       it's not supported by the built-in libgcrypt, and we won't be able 
> > to
> > +       calculate the PCR digest, so SHA384 is marked as unsupported. */
> > +    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 == NULL)
> > +    {
> > +      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 %" PRIuGRUB_SIZE " 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 (TPM2_StartAuthSession: 
> > 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 (TPM2_PolicyPCR: 
> > 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 
> > (TPM2_PolicyGetDigest: 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;
> > +
> > +  if (args->tpm2_srk != 0)
> > +    {
> > +      /* Find SRK */
> > +      rc = TPM2_ReadPublic (args->tpm2_srk, NULL, &public);
> > +      if (rc == TPM_RC_SUCCESS)
> > +   {
> > +     printf (_("Read SRK from 0x%x\n"), args->tpm2_srk);
> > +     *srk = args->tpm2_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)
> > +   {
> > +     fprintf (stderr,
> > +              _("Failed to retrieve SRK from 0x%x (TPM2_ReadPublic: 
> > 0x%x).\n"),
> > +              args->tpm2_srk, rc);
> > +     return GRUB_ERR_BAD_DEVICE;
> > +   }
> > +    }
> > +
> > +  /* Create SRK */
> > +  authCommand.sessionHandle = TPM_RS_PW;
> > +  inPublic.publicArea.type = args->srk_type.type;
> > +  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->srk_type.type)
> > +    {
> > +    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 = 
> > args->srk_type.detail.rsa_bits;
> 
> Same comment here about pairing RSA3072 with AES-256 and SHA-512 maybe
> (since SHA 384 isn't supported here).
> 
It's sad that we don't have native SHA384 support due to the outdated
libgcrypt :(

> Rest LGTM.
> 
Thanks for reviewing the patch!

Gary Lin


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

Reply via email to