[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [PATCH v21 25/33] util/grub-protect: Add new tool
From: |
Daniel Kiper |
Subject: |
Re: [PATCH v21 25/33] util/grub-protect: Add new tool |
Date: |
Tue, 5 Nov 2024 16:19:11 +0100 |
On Mon, Nov 04, 2024 at 03:31:58PM +0800, Gary Lin wrote:
> From: Hernan Gatta <hegatta@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/efi/grub/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/efi/grub/sealed.key
>
> Then, in the boot script, for TPM 2.0 Key File:
>
> tpm2_key_protector_init --tpm2key=(hd0,gpt1)/efi/grub/sealed.tpm
> cryptomount -u <SDB1_UUID> -P tpm2
>
> Or, for the raw sealed key:
>
> tpm2_key_protector_init --keyfile=(hd0,gpt1)/efi/grub/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.
>
> Cc: Stefan Berger <stefanb@linux.ibm.com>
> Signed-off-by: Hernan Gatta <hegatta@linux.microsoft.com>
> Signed-off-by: Gary Lin <glin@suse.com>
> ---
> .gitignore | 2 +
> Makefile.util.def | 26 +
> configure.ac | 30 +
> docs/man/grub-protect.h2m | 4 +
> util/grub-protect.c | 1407 +++++++++++++++++++++++++++++++++++++
> 5 files changed, 1469 insertions(+)
> create mode 100644 docs/man/grub-protect.h2m
> create mode 100644 util/grub-protect.c
>
> diff --git a/.gitignore b/.gitignore
> index 4c1f91db8..2105d87c8 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 fb82f59a0..074c0aff7 100644
> --- a/Makefile.util.def
> +++ b/Makefile.util.def
> @@ -208,6 +208,32 @@ program = {
> ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
> };
>
> +program = {
> + name = grub-protect;
> + mansection = 1;
> +
> + common = grub-core/kern/emu/argp_common.c;
> + common = grub-core/osdep/init.c;
> + common = grub-core/lib/tss2/buffer.c;
> + common = grub-core/lib/tss2/tss2_mu.c;
> + common = grub-core/lib/tss2/tpm2_cmd.c;
> + common = grub-core/commands/tpm2_key_protector/args.c;
> + common = grub-core/commands/tpm2_key_protector/tpm2key_asn1_tab.c;
> + common = util/grub-protect.c;
> + common = util/probe.c;
> +
> + cflags = '-I$(srcdir)/grub-core/lib/tss2
> -I$(srcdir)/grub-core/commands/tpm2_key_protector';
> +
> + 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 458b8382b..ad1e7bea5 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])
> @@ -2068,6 +2069,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])
> @@ -2184,6 +2208,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
> @@ -2311,6 +2336,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/docs/man/grub-protect.h2m b/docs/man/grub-protect.h2m
> new file mode 100644
> index 000000000..ecf1c9eab
> --- /dev/null
> +++ b/docs/man/grub-protect.h2m
> @@ -0,0 +1,4 @@
> +[NAME]
> +grub-protect \- protect a disk key with a key protector
> +[DESCRIPTION]
> +grub-protect helps to protect a disk encryption key with a specified key
> protector.
> diff --git a/util/grub-protect.c b/util/grub-protect.c
> new file mode 100644
> index 000000000..a120529ef
> --- /dev/null
> +++ b/util/grub-protect.c
> @@ -0,0 +1,1407 @@
> +/*
> + * GRUB -- GRand Unified Bootloader
> + * Copyright (C) 2022 Microsoft Corporation
> + * Copyright (C) 2023 SUSE LLC
> + * Copyright (C) 2024 Free Software Foundation, Inc.
> + *
> + * 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/emu/hostdisk.h>
> +#include <grub/emu/misc.h>
> +
> +#include <grub/util/misc.h>
> +
> +#include <tss2_buffer.h>
> +#include <tss2_mu.h>
> +#include <tcg2.h>
> +#include <tpm2_args.h>
> +#include <tpm2.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 protect_opt
> +{
> + /* General */
> + PROTECT_OPT_ACTION = 'a',
> + PROTECT_OPT_PROTECTOR = 'p',
> + /* TPM2 */
> + PROTECT_OPT_TPM2_DEVICE = 0x100,
> + PROTECT_OPT_TPM2_PCRS,
> + PROTECT_OPT_TPM2_ASYMMETRIC,
> + PROTECT_OPT_TPM2_BANK,
> + PROTECT_OPT_TPM2_SRK,
> + PROTECT_OPT_TPM2_KEYFILE,
> + PROTECT_OPT_TPM2_OUTFILE,
> + PROTECT_OPT_TPM2_EVICT,
> + PROTECT_OPT_TPM2_TPM2KEY
> +} protect_opt_t;
> +
> +/* Option flags to keep track of specified arguments */
> +typedef enum protect_arg
> +{
> + /* General */
> + PROTECT_ARG_ACTION = 1 << 0,
> + PROTECT_ARG_PROTECTOR = 1 << 1,
> + /* TPM2 */
> + PROTECT_ARG_TPM2_DEVICE = 1 << 2,
> + PROTECT_ARG_TPM2_PCRS = 1 << 3,
> + PROTECT_ARG_TPM2_ASYMMETRIC = 1 << 4,
> + PROTECT_ARG_TPM2_BANK = 1 << 5,
> + PROTECT_ARG_TPM2_SRK = 1 << 6,
> + PROTECT_ARG_TPM2_KEYFILE = 1 << 7,
> + PROTECT_ARG_TPM2_OUTFILE = 1 << 8,
> + PROTECT_ARG_TPM2_EVICT = 1 << 9,
> + PROTECT_ARG_TPM2_TPM2KEY = 1 << 10
> +} protect_arg_t;
> +
> +typedef enum protect_protector
> +{
> + PROTECT_TYPE_ERROR,
> + PROTECT_TYPE_TPM2
> +} protect_protector_t;
> +
> +typedef enum protect_action
> +{
> + PROTECT_ACTION_ERROR,
> + PROTECT_ACTION_ADD,
> + PROTECT_ACTION_REMOVE
> +} protect_action_t;
> +
> +typedef struct protect_args
> +{
> + protect_arg_t args;
> + protect_action_t action;
> + 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_t tpm2_bank;
> + TPM_HANDLE_t tpm2_srk;
> + const char *tpm2_keyfile;
> + const char *tpm2_outfile;
> + int tpm2_evict;
> + int tpm2_tpm2key;
AFAICT the tpm2_evict and tpm2_tpm2key should be defined as bool.
> +} protect_args_t;
[...]
> +static error_t
> +protect_argp_parser (int key, char *arg, struct argp_state *state)
> +{
> + grub_err_t err;
> + protect_args_t *args = state->input;
> +
> + switch (key)
> + {
> + case PROTECT_OPT_ACTION:
> + if (args->args & PROTECT_ARG_ACTION)
> + {
> + fprintf (stderr, N_("--action|-a can only be specified once.\n"));
> + return EINVAL;
> + }
> +
> + if (grub_strcmp (arg, "add") == 0)
> + args->action = PROTECT_ACTION_ADD;
> + else if (grub_strcmp (arg, "remove") == 0)
> + args->action = PROTECT_ACTION_REMOVE;
> + else
> + {
> + fprintf (stderr, N_("'%s' is not a valid action.\n"), arg);
> + return EINVAL;
> + }
> +
> + args->args |= PROTECT_ARG_ACTION;
> + break;
> +
> + case PROTECT_OPT_PROTECTOR:
> + if (args->args & PROTECT_ARG_PROTECTOR)
> + {
> + fprintf (stderr, N_("--protector|-p can only be specified once.\n"));
> + return EINVAL;
> + }
> +
> + if (grub_strcmp (arg, "tpm2") == 0)
> + args->protector = PROTECT_TYPE_TPM2;
> + else
> + {
> + fprintf (stderr, N_("'%s' is not a valid protector.\n"), arg);
> + return EINVAL;
> + }
> +
> + args->args |= PROTECT_ARG_PROTECTOR;
> + break;
> +
> + case PROTECT_OPT_TPM2_DEVICE:
> + if (args->args & PROTECT_ARG_TPM2_DEVICE)
> + {
> + fprintf (stderr, N_("--tpm2-device can only be specified once.\n"));
> + return EINVAL;
> + }
> +
> + args->tpm2_device = xstrdup(arg);
Missing space before "(". Please fix this here and in other places too.
If you fix these minor issues and problems mentioned by Stefan you can
add Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>.
Daniel
- Re: [PATCH v21 21/33] tss2: Add TPM2 types and Marshal/Unmarshal functions, (continued)
- [PATCH v21 22/33] tss2: Add TPM2 Software Stack (TSS2) support, Gary Lin, 2024/11/04
- [PATCH v21 23/33] key_protector: Add TPM2 Key Protector, Gary Lin, 2024/11/04
- [PATCH v21 24/33] cryptodisk: Support key protectors, Gary Lin, 2024/11/04
- [PATCH v21 25/33] util/grub-protect: Add new tool, Gary Lin, 2024/11/04
- [PATCH v21 26/33] tpm2_key_protector: Support authorized policy, Gary Lin, 2024/11/04
- [PATCH v21 27/33] tpm2_key_protector: Implement NV index, Gary Lin, 2024/11/04
- [PATCH v21 28/33] cryptodisk: Fallback to passphrase, Gary Lin, 2024/11/04
- [PATCH v21 29/33] cryptodisk: wipe out the cached keys from protectors, Gary Lin, 2024/11/04
- [PATCH v21 31/33] tpm2_key_protector: Add grub-emu support, Gary Lin, 2024/11/04
- [PATCH v21 30/33] diskfilter: look up cryptodisk devices first, Gary Lin, 2024/11/04
- [PATCH v21 32/33] tests: Add tpm2_key_protector_test, Gary Lin, 2024/11/04
- [PATCH v21 33/33] docs: Document TPM2 key protector, Gary Lin, 2024/11/04