The systemd TPM2 key protector is a module that enables the automatic
retrieval
of a fully-encrypted disk's unlocking key from a systemd token in luks2
partition header.
Inspired by the tpm2_key_protector module and the cryptsetup systemd
implementation.
The systemd TPM2 key protector registers two commands:
- systemd_tpm2_key_protector_init: Initializes the state of the TPM2 key
protector for later usage, clearing any
previous state, too, if any.
- systemd_tpm2_key_protector_clear: Clears any state set by
systemd_tpm2_key_protector_init.
Create the token inside LUKS2 header using TPM2 device:
systemd-cryptenroll /dev/sdXY --tpm2-device=auto
Mount the partition in GRUB2:
systemd_tpm2_key_protector_init --device=hdX,gptY
cryptomount hdX,gptY -P systemd-tpm2
New tpm2srk module is created in order to factorize the code between
tpm2_key_protector and systemd_tpm2_key_protector.
New base64 module is created in order to factorize the code between
luks2 and systemd_tpm2_key_protector.
Exposing some structures and functions from luks2 notably the new
luks2_iterate_keyslot function and adding the token parsing code
in luks2_get_keyslot.
Signed-off-by: Diorcet Yann <diorcet.y...@gmail.com>
---
Makefile.util.def | 1 +
grub-core/Makefile.core.def | 28 +-
.../systemd_tpm2_key_protector/module.c | 346 ++++++++++++++++++
.../systemd_tpm2_key_protector/tpm2_luks2.c | 238 ++++++++++++
.../systemd_tpm2_key_protector/tpm2_luks2.h | 37 ++
.../commands/tpm2_key_protector/module.c | 171 +--------
.../commands/tpm2_key_protector/tpm2_args.h | 13 +-
grub-core/disk/luks2.c | 252 +++++++++----
grub-core/lib/base64.c | 21 ++
grub-core/lib/tpm2srk.c | 191 ++++++++++
include/grub/luks2.h | 148 ++++++++
.../grub}/tpm2.h | 11 +
include/grub/tpm2srk.h | 44 +++
util/grub-protect.c | 60 +--
14 files changed, 1259 insertions(+), 302 deletions(-)
create mode 100644 grub-core/commands/systemd_tpm2_key_protector/module.c
create mode 100644
grub-core/commands/systemd_tpm2_key_protector/tpm2_luks2.c
create mode 100644
grub-core/commands/systemd_tpm2_key_protector/tpm2_luks2.h
create mode 100644 grub-core/lib/base64.c
create mode 100644 grub-core/lib/tpm2srk.c
create mode 100644 include/grub/luks2.h
rename {grub-core/commands/tpm2_key_protector => include/grub}/tpm2.h
(85%)
create mode 100644 include/grub/tpm2srk.h
diff --git a/Makefile.util.def b/Makefile.util.def
index 3a80e6d28..744ff6337 100644
--- a/Makefile.util.def
+++ b/Makefile.util.def
@@ -213,6 +213,7 @@ program = {
common = grub-core/kern/emu/argp_common.c;
common = grub-core/osdep/init.c;
+ common = grub-core/lib/tpm2srk.c;
common = grub-core/lib/tss2/buffer.c;
common = grub-core/lib/tss2/tss2_mu.c;
common = grub-core/lib/tss2/tpm2_cmd.c;
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index f6d312033..792460e54 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -1215,6 +1215,14 @@ module = {
common = lib/json/json.c;
};
+module = {
+ name = base64;
+ common = lib/gnulib/base64.c;
+ common = lib/base64.c;
+ cflags = '$(CFLAGS_POSIX) $(CFLAGS_GNULIB)';
+ cppflags = '$(CPPFLAGS_POSIX) $(CPPFLAGS_GNULIB)';
+};
+
module = {
name = afsplitter;
common = disk/AFSplitter.c;
@@ -1228,7 +1236,6 @@ module = {
module = {
name = luks2;
common = disk/luks2.c;
- common = lib/gnulib/base64.c;
cflags = '$(CFLAGS_POSIX) $(CFLAGS_GNULIB)';
cppflags = '$(CPPFLAGS_POSIX) $(CPPFLAGS_GNULIB) -I$(srcdir)/lib/json';
};
@@ -2570,6 +2577,14 @@ module = {
cppflags = '-I$(srcdir)/lib/tss2';
};
+module = {
+ name = tpm2srk;
+ common = lib/tpm2srk.c;
+ enable = efi;
+ enable = emu;
+ cppflags = '-I$(srcdir)/lib/tss2';
+};
+
module = {
name = tpm2_key_protector;
common = commands/tpm2_key_protector/args.c;
@@ -2582,6 +2597,17 @@ module = {
cppflags = '-I$(srcdir)/lib/tss2 -I$(srcdir)/lib/libtasn1-grub';
};
+module = {
+ name = systemd_tpm2_key_protector;
+ common = commands/systemd_tpm2_key_protector/tpm2_luks2.c;
+ common = commands/systemd_tpm2_key_protector/module.c;
+ /* The plaform support of systemd_tpm2_key_protector depends on the
tcg2 implementation in tss2. */
+ enable = efi;
+ enable = emu;
+ cflags = '$(CFLAGS_POSIX) $(CFLAGS_GNULIB)';
+ cppflags = '$(CPPFLAGS_POSIX) $(CPPFLAGS_GNULIB) -I$(srcdir)/lib/json
-I$(srcdir)/lib/tss2';
+};
+
module = {
name = tr;
common = commands/tr.c;
diff --git a/grub-core/commands/systemd_tpm2_key_protector/module.c
b/grub-core/commands/systemd_tpm2_key_protector/module.c
new file mode 100644
index 000000000..827e93c04
--- /dev/null
+++ b/grub-core/commands/systemd_tpm2_key_protector/module.c
@@ -0,0 +1,346 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * 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 <grub/dl.h>
+#include <grub/extcmd.h>
+#include <grub/file.h>
+#include <grub/list.h>
+#include <grub/misc.h>
+#include <grub/err.h>
+#include <grub/mm.h>
+#include <grub/key_protector.h>
+
+#include <base64.h>
+
+#include <grub/luks2.h>
+
+#include "tpm2_luks2.h"
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+typedef enum systemd_tpm2_protector_device
+{
+ SYSTEMD_TPM2_PROTECTOR_DEVICE_UNSET,
+ SYSTEMD_TPM2_PROTECTOR_DEVICE_SET,
+} systemd_tpm2_protector_device_t;
+
+typedef enum tpm2_protector_options
+{
+ OPTION_DEVICE,
+} systemd_tpm2_protector_options_t;
+
+typedef struct systemd_tpm2_protector_context
+{
+ systemd_tpm2_protector_device_t mode;
+ grub_luks2_token_t token;
+} systemd_tpm2_protector_context_t;
+
+static const struct grub_arg_option
systemd_tpm2_protector_init_cmd_options[] =
+ {
+ {
+ .longarg = "device",
+ .shortarg = 'd',
+ .flags = 0,
+ .arg = NULL,
+ .type = ARG_TYPE_STRING,
+ .doc = N_("Set LUKS partition to use"),
+ },
+ /* End of list */
+ {0, 0, 0, 0, 0, 0}
+ };
+
+static grub_extcmd_t systemd_tpm2_protector_init_cmd;
+static grub_extcmd_t systemd_tpm2_protector_clear_cmd;
+static systemd_tpm2_protector_context_t systemd_tpm2_protector_ctx = {0};
+
+static inline int
+hex2val (char hex)
+{
+ if ('0' <= hex && hex <= '9')
+ return hex - '0';
+ if ('a' <= hex && hex <= 'f')
+ return hex - 'a' + 10;
+ if ('A' <= hex && hex <= 'F')
+ return hex - 'A' + 10;
+ return -1;
+}
+
+static grub_err_t
+unhex_hash (const char *p, idx_t l, void **ret, idx_t *ret_len) {
+ char *buf = NULL;
+ idx_t buf_size;
+ char *z;
+ int r = GRUB_ERR_NONE;
+
+ if (p == NULL || l == 0 || ret == NULL || ret_len == NULL)
+ return GRUB_ERR_BAD_ARGUMENT;
+
+ if (l == SIZE_MAX)
+ l = grub_strlen(p);
+
+ /* Note that the calculation of memory size is an upper boundary,
+ as we ignore whitespace while decoding */
+ buf_size = (l + 1) / 2 + 1;
+ buf = z = grub_malloc(buf_size);
+ if (!buf)
+ return GRUB_ERR_OUT_OF_MEMORY;
+
+ while (p[0] != 0)
+ {
+ int high, low;
+
+ /* Remove spaces before first hex character */
+ while (p[0] != 0 && grub_isspace (p[0]))
+ p++;
+
+ /* End of the string */
+ if (p[0] == 0)
+ break;
+
+ /* First hex character */
+ high = hex2val (*p++);
+
+ /* Remove spaces after first hex character */
+ while (p[0] != 0 && grub_isspace (p[0]))
+ p++;
+ if (p[0] == 0 || high < 0)
+ {
+ grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid hex string");
+ goto on_failure;
+ }
+
+ /* Second hex character */
+ low = hex2val (*p++);
+ if (low < 0)
+ {
+ grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid hex string");
+ goto on_failure;
+ }
+
+ *z++ = (high << 4) | low;
+ }
+
+ *z = 0;
+
+ *ret_len = (size_t) (z - buf);
+ *ret = buf;
+
+ return r;
+
+on_failure:
+ grub_free(buf);
+ *ret = NULL;
+ *ret_len = 0;
+
+ return r;
+}
+
+static grub_err_t
+systemd_tpm2_protector_recover_key (grub_uint8_t **key, grub_size_t
*key_size)
+{
+ const char *base64_blob;
+ char *blob;
+ idx_t blob_size;
+ void *decrypted_key;
+ grub_size_t decrypted_key_size;
+ char *base64_encode;
+ idx_t base64_encode_size;
+
+ const char *hex_hash;
+ char *policy_hash;
+ idx_t policy_hash_size;
+ grub_err_t ret = GRUB_ERR_NONE;
+
+ /* Expect a call to systemd_tpm2_protector_init before anybody tries
to use us */
+ if (systemd_tpm2_protector_ctx.mode ==
SYSTEMD_TPM2_PROTECTOR_DEVICE_UNSET)
+ return grub_error (GRUB_ERR_INVALID_COMMAND, N_("cannot use systemd
TPM2 key protector without initializing it, call
systemd_tpm2_protector_init first"));
+
+ if (key == NULL || key_size == NULL)
+ return GRUB_ERR_BAD_ARGUMENT;
+
+ base64_blob =
systemd_tpm2_protector_ctx.token.u.systemd_tpm2.base64_blob;
+ if(base64_decode_alloc(base64_blob, grub_strlen (base64_blob), &blob,
&blob_size) == 0)
+ {
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Can't decode base64
blob"));
+ }
+
+ hex_hash =
systemd_tpm2_protector_ctx.token.u.systemd_tpm2.hex_policy_hash;
+ ret = unhex_hash(hex_hash, grub_strlen (hex_hash),
(void*)&policy_hash, &policy_hash_size);
+ if(ret != GRUB_ERR_NONE)
+ {
+ ret = grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Can't unhex policy
hash"));
+ goto exit1;
+ }
+
+ ret = tpm2_luks2_acquire_luks2_key(
+ systemd_tpm2_protector_ctx.token.u.systemd_tpm2.pcr_mask,
+ systemd_tpm2_protector_ctx.token.u.systemd_tpm2.pcr_bank,
+ systemd_tpm2_protector_ctx.token.u.systemd_tpm2.primary_alg,
+ blob,
+ blob_size,
+ policy_hash,
+ policy_hash_size,
+ &decrypted_key,
+ &decrypted_key_size);
+
+ if (ret != GRUB_ERR_NONE)
+ goto exit2;
+
+ /* Before using this key as passphrase we base64 encode it, for
compat with homed */
+ base64_encode_size = base64_encode_alloc(decrypted_key,
decrypted_key_size, &base64_encode);
+ if (base64_encode_size <= 0)
+ {
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Can't encode
passphrase"));
+ goto exit3;
+ }
+
+ *key = (grub_uint8_t *) base64_encode;
+ *key_size = grub_strlen(base64_encode);
+
+exit3:
+ grub_free(decrypted_key);
+exit2:
+ grub_free(policy_hash);
+exit1:
+ grub_free(blob);
+
+ return ret;
+}
+
+static grub_err_t
+tpm2_protector_parse_device (const char *value, const char **file)
+{
+ if (grub_strlen (value) == 0)
+ return GRUB_ERR_BAD_ARGUMENT;
+
+ *file = value;
+
+ return GRUB_ERR_NONE;
+}
+
+static void
+luks2_iterate_fct(grub_luks2_keyslot_t *k __attribute__ ((unused)),
+ grub_luks2_digest_t *d __attribute__ ((unused)),
+ grub_luks2_segment_t *s __attribute__ ((unused)),
+ grub_luks2_token_t *t)
+{
+ grub_memcpy(&systemd_tpm2_protector_ctx.token, t,
sizeof(grub_luks2_token_t));
+ systemd_tpm2_protector_ctx.token.u.systemd_tpm2.base64_blob =
+ grub_strdup(systemd_tpm2_protector_ctx.token.u.systemd_tpm2.base64_blob);
+ systemd_tpm2_protector_ctx.token.u.systemd_tpm2.hex_policy_hash =
+
grub_strdup(systemd_tpm2_protector_ctx.token.u.systemd_tpm2.hex_policy_hash);
+}
+
+static grub_err_t
+systemd_tpm2_protector_init_cmd_handler (grub_extcmd_context_t ctxt,
int argc,
+ char **args __attribute__
((unused)))
+{
+ grub_err_t err;
+ struct grub_arg_list *state = ctxt->state;
+ const char *device = NULL;
+
+ if (systemd_tpm2_protector_ctx.token.u.systemd_tpm2.base64_blob != NULL)
+ grub_free((void
*)systemd_tpm2_protector_ctx.token.u.systemd_tpm2.base64_blob);
+ if (systemd_tpm2_protector_ctx.token.u.systemd_tpm2.hex_policy_hash
!= NULL)
+ grub_free((void
*)systemd_tpm2_protector_ctx.token.u.systemd_tpm2.hex_policy_hash);
+ grub_memset (&systemd_tpm2_protector_ctx, 0, sizeof
(systemd_tpm2_protector_ctx));
+
+ if (argc != 0)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
N_("systemd_tpm2_key_protector_init accepts no arguments"));
+
+ if (state[OPTION_DEVICE].set) /* device */
+ {
+ err = tpm2_protector_parse_device (state[OPTION_DEVICE].arg,
&device);
+ if (err != GRUB_ERR_NONE)
+ return err;
+ }
+
+ if (device == NULL)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
N_("systemd_tpm2_key_protector_init: no device provided"));
+
+ /* Open disk. */
+ grub_disk_t disk = grub_disk_open (device);
+ if (! disk)
+ {
+ err = grub_error (GRUB_ERR_BAD_ARGUMENT,
N_("systemd_tpm2_key_protector_init: can't open device %s"), device);
+ goto error;
+ }
+
+ luks2_iterate_keyslot(disk, LUKS2_ITERATE_FLAGS_WITH_TOKEN,
luks2_iterate_fct);
+
+ if (systemd_tpm2_protector_ctx.token.type !=
LUKS2_TOKEN_TYPE_SYSTEMD_TPM2)
+ err = grub_error (GRUB_ERR_BAD_ARGUMENT,
N_("systemd_tpm2_key_protector_init: no systemd-tpm2 token found on
%s"), device);
+ else
+ systemd_tpm2_protector_ctx.mode = SYSTEMD_TPM2_PROTECTOR_DEVICE_SET;
+
+ grub_disk_close(disk);
+
+error:
+ return err;
+}
+
+static grub_err_t
+systemd_tpm2_protector_clear_cmd_handler (grub_extcmd_context_t ctxt
__attribute__ ((unused)),
+ int argc, char **args __attribute__
((unused)))
+{
+ if (argc != 0)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
N_("systemd_tpm2_key_protector_clear accepts no arguments"));
+
+ if (systemd_tpm2_protector_ctx.token.u.systemd_tpm2.base64_blob != NULL)
+ grub_free((void
*)systemd_tpm2_protector_ctx.token.u.systemd_tpm2.base64_blob);
+ if (systemd_tpm2_protector_ctx.token.u.systemd_tpm2.hex_policy_hash
!= NULL)
+ grub_free((void
*)systemd_tpm2_protector_ctx.token.u.systemd_tpm2.hex_policy_hash);
+ grub_memset (&systemd_tpm2_protector_ctx, 0, sizeof
(systemd_tpm2_protector_ctx));
+
+ return GRUB_ERR_NONE;
+}
+
+static struct grub_key_protector systemd_tpm2_key_protector =
+ {
+ .name = "systemd-tpm2",
+ .recover_key = systemd_tpm2_protector_recover_key
+ };
+
+GRUB_MOD_INIT (systemd_tpm2_key_protector)
+{
+ grub_memset (&systemd_tpm2_protector_ctx, 0, sizeof
(systemd_tpm2_protector_ctx));
+ systemd_tpm2_protector_init_cmd =
+ grub_register_extcmd ("systemd_tpm2_key_protector_init",
+ systemd_tpm2_protector_init_cmd_handler, 0,
+ N_("device "),
+ N_("Initialize the systemd TPM2 key protector."),
+ systemd_tpm2_protector_init_cmd_options);
+ systemd_tpm2_protector_clear_cmd =
+ grub_register_extcmd ("systemd_tpm2_key_protector_clear",
+ systemd_tpm2_protector_clear_cmd_handler, 0, NULL,
+ N_("Clear the systemd TPM2 key protector if
previously initialized."),
+ NULL);
+ grub_key_protector_register (&systemd_tpm2_key_protector);
+
+}
+
+GRUB_MOD_FINI (systemd_tpm2_key_protector)
+{
+ if (systemd_tpm2_protector_ctx.token.u.systemd_tpm2.base64_blob != NULL)
+ grub_free((void
*)systemd_tpm2_protector_ctx.token.u.systemd_tpm2.base64_blob);
+ if (systemd_tpm2_protector_ctx.token.u.systemd_tpm2.hex_policy_hash
!= NULL)
+ grub_free((void
*)systemd_tpm2_protector_ctx.token.u.systemd_tpm2.hex_policy_hash);
+ grub_key_protector_unregister (&systemd_tpm2_key_protector);
+ grub_unregister_extcmd (systemd_tpm2_protector_clear_cmd);
+ grub_unregister_extcmd (systemd_tpm2_protector_init_cmd);
+}
diff --git a/grub-core/commands/systemd_tpm2_key_protector/tpm2_luks2.c
b/grub-core/commands/systemd_tpm2_key_protector/tpm2_luks2.c
new file mode 100644
index 000000000..d07344a38
--- /dev/null
+++ b/grub-core/commands/systemd_tpm2_key_protector/tpm2_luks2.c
@@ -0,0 +1,238 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * 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 "tpm2_luks2.h"
+
+#include <grub/list.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/luks2.h>
+#include <grub/tpm2.h>
+#include <grub/tpm2srk.h>
+
+#include <tss2_buffer.h>
+#include <tss2_mu.h>
+
+static grub_err_t
+tpm2_luks2_unmarshal_raw (const void *sealed_key,
+ grub_size_t sealed_key_size,
+ tpm2_sealed_key_t *sk)
+{
+ struct grub_tpm2_buffer buf;
+
+ grub_tpm2_buffer_init (&buf);
+ if (sealed_key_size > buf.cap)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("sealed key larger
than %llu bytes"), (unsigned long long)buf.cap);
+
+ grub_memcpy (buf.data, sealed_key, sealed_key_size);
+ buf.size = sealed_key_size;
+
+ grub_Tss2_MU_TPM2B_PRIVATE_Unmarshal (&buf, &sk->private);
+ grub_Tss2_MU_TPM2B_PUBLIC_Unmarshal (&buf, &sk->public);
+
+ if (buf.error != 0)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("malformed TPM wire
key file"));
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+tpm2_luks2_make_pcr_session(TPMI_SH_AUTH_SESSION_t session,
grub_uint32_t pcr_mask, grub_uint16_t pcr_bank, TPM2B_DIGEST_t *digest)
+{
+ grub_uint16_t i;
+
+ TPM_RC_t rc;
+ TPM2B_DIGEST_t pcr_digest = {0};
+ TPM2B_DIGEST_t policy_digest = {0};
+ TPML_PCR_SELECTION_t pcr_sel = {
+ .count = 1,
+ .pcrSelections = {
+ {
+ .hash = 0,
+ .sizeOfSelect = 3,
+ .pcrSelect = {0}
+ },
+ }
+ };
+
+ /* Specify the bank */
+ if (pcr_bank == LUKS2_TOKEN_SYSTEMD_TPM2_PCR_BANK_TYPE_SHA256)
+ {
+ pcr_sel.pcrSelections[0].hash = TPM_ALG_SHA256;
+ }
+ else if (LUKS2_TOKEN_SYSTEMD_TPM2_PCR_BANK_TYPE_SHA1)
+ {
+ pcr_sel.pcrSelections[0].hash = TPM_ALG_SHA1;
+ }
+ else
+ {
+ return GRUB_ERR_BAD_ARGUMENT;
+ }
+
+ /* Convert PCR mask to PCR selection */
+ for(i = 0; i < TPM_MAX_PCRS; ++i)
+ if ((pcr_mask & (1 << i)) != 0)
+ TPMS_PCR_SELECTION_SelectPCR (&pcr_sel.pcrSelections[0], i);
+
+ /* PCR Policy */
+ rc = grub_tpm2_policypcr (session, NULL, &pcr_digest, &pcr_sel, NULL);
+ if (rc != TPM_RC_SUCCESS)
+ {
+ return grub_error (GRUB_ERR_BAD_DEVICE, "Failed to submit PCR
policy (TPM2_PolicyPCR: 0x%x).", rc);
+ }
+
+ /* Retrieve Policy Digest */
+ rc = grub_tpm2_policygetdigest (session, NULL, &policy_digest, NULL);
+ if (rc != TPM_RC_SUCCESS)
+ {
+ return grub_error (GRUB_ERR_BAD_DEVICE, "failed to get policy
digest (TPM2_PolicyGetDigest: 0x%x).", rc);
+ }
+
+ *digest = policy_digest;
+ return GRUB_ERR_NONE;
+}
+
+grub_err_t
+tpm2_luks2_acquire_luks2_key(
+ grub_uint32_t pcr_mask,
+ grub_uint16_t pcr_bank,
+ grub_uint16_t primary_alg,
+ const void *key_data,
+ grub_size_t key_data_size,
+ const void *policy_hash,
+ grub_size_t policy_hash_size,
+ void **ret_decrypted_key,
+ grub_size_t *ret_decrypted_key_size) {
+
+ tpm2_sealed_key_t sk;
+ grub_srk_type_t srk_type;
+
+ grub_err_t err;
+ grub_uint8_t *key_out;
+
+ TPM_HANDLE_t parent_handle = 0;
+ TPM_HANDLE_t sealed_handle = 0;
+ TPM_HANDLE_t srk_handle = 0;
+ TPMS_AUTH_COMMAND_t authCmd = {0};
+ TPM2B_NONCE_t nonceCaller = {0};
+ TPMT_SYM_DEF_t symmetric = {0};
+ TPM2B_DIGEST_t pcr_digest = {0};
+ TPM_RC_t rc;
+ TPMI_SH_AUTH_SESSION_t session;
+ TPM2B_SENSITIVE_DATA_t data;
+
+ if (ret_decrypted_key == NULL || ret_decrypted_key_size == NULL)
+ {
+ return GRUB_ERR_BAD_ARGUMENT;
+ }
+
+ /* Decode blob: PRIVATE + PUBLIC */
+ err = tpm2_luks2_unmarshal_raw(key_data, key_data_size, &sk);
+ if (err != GRUB_ERR_NONE)
+ {
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Can't unmarshal blob");
+ }
+
+ /* Use specified algo */
+ if (primary_alg == LUKS2_TOKEN_SYSTEMD_TPM2_ALGO_TYPE_ECC)
+ {
+ srk_type.noDA = false;
+ srk_type.type = TPM_ALG_ECC;
+ srk_type.detail.ecc_curve = TPM_ECC_NIST_P256;
+ }
+ else if (LUKS2_TOKEN_SYSTEMD_TPM2_ALGO_TYPE_RSA)
+ {
+ srk_type.noDA = false;
+ srk_type.type = TPM_ALG_RSA;
+ srk_type.detail.rsa_bits = 2048;
+ }
+ else
+ {
+ return GRUB_ERR_BAD_ARGUMENT;
+ }
+
+ parent_handle = TPM_RH_OWNER;
+ if (TPM_HT_IS_PERSISTENT (parent_handle))
+ srk_handle = parent_handle;
+
+ /* Load SRK and sealed and get handles */
+ err = tpm2_protector_srk_load(srk_type, &sk, parent_handle,
&sealed_handle, &srk_handle);
+ if (err != GRUB_ERR_NONE)
+ {
+ grub_print_error ();
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Can't load srk");
+ }
+
+ /* Start Auth Session */
+ nonceCaller.size = TPM_SHA256_DIGEST_SIZE;
+ symmetric.algorithm = TPM_ALG_NULL;
+ rc = grub_tpm2_startauthsession (TPM_RH_NULL, TPM_RH_NULL, NULL,
&nonceCaller, NULL,
+ TPM_SE_POLICY, &symmetric,
TPM_ALG_SHA256,
+ &session, NULL, NULL);
+ if (rc != TPM_RC_SUCCESS)
+ {
+ err = grub_error (GRUB_ERR_BAD_DEVICE, "failed to start auth
session (TPM2_StartAuthSession: 0x%x)", rc);
+ goto exit1;
+ }
+
+ /* Create PCR digest from the given setting */
+ err = tpm2_luks2_make_pcr_session(session, pcr_mask, pcr_bank,
&pcr_digest);
+ if(err != GRUB_ERR_NONE)
+ goto exit2;
+
+ /* Compare the computed digest with the joined one */
+ if (policy_hash_size > 0 && ( policy_hash_size != pcr_digest.size ||
grub_memcmp(pcr_digest.buffer, policy_hash, policy_hash_size)))
+ {
+ err = grub_error (GRUB_ERR_BAD_DEVICE, "Current policy digest
does not match stored policy digest, cancelling TPM2 authentication
attempt.");
+ goto exit2;
+ }
+
+ /* Unseal Sealed Key */
+ authCmd.sessionHandle = session;
+ rc = grub_tpm2_unseal (sealed_handle, &authCmd, &data, NULL);
+ if (rc != TPM_RC_SUCCESS)
+ {
+ err = grub_error (GRUB_ERR_BAD_DEVICE, "failed to unseal sealed
key (TPM2_Unseal: 0x%x)", rc);
+ goto exit2;
+ }
+
+ /* Epilogue */
+ key_out = grub_malloc (data.size);
+ if (key_out == NULL)
+ {
+ err = grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("no memory left to
allocate unlock key buffer"));
+ goto exit2;
+ }
+
+ grub_memcpy (key_out, data.buffer, data.size);
+
+ *ret_decrypted_key = key_out;
+ *ret_decrypted_key_size = data.size;
+
+ err = GRUB_ERR_NONE;
+
+ exit2:
+ grub_tpm2_flushcontext (session);
+ exit1:
+ grub_tpm2_flushcontext (sealed_handle);
+
+ if (!TPM_HT_IS_PERSISTENT (srk_handle))
+ grub_tpm2_flushcontext (srk_handle);
+
+ return err;
+}
\ No newline at end of file
diff --git a/grub-core/commands/systemd_tpm2_key_protector/tpm2_luks2.h
b/grub-core/commands/systemd_tpm2_key_protector/tpm2_luks2.h
new file mode 100644
index 000000000..b00c42868
--- /dev/null
+++ b/grub-core/commands/systemd_tpm2_key_protector/tpm2_luks2.h
@@ -0,0 +1,37 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * 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/>.
+ */
+
+#ifndef GRUB_SYSTEMD_TPM2_LUKS2_TPM2_HEADER
+#define GRUB_SYSTEMD_TPM2_LUKS2_TPM2_HEADER 1
+
+#include <grub/types.h>
+#include <grub/err.h>
+
+extern grub_err_t
+tpm2_luks2_acquire_luks2_key(
+ grub_uint32_t pcr_mask,
+ grub_uint16_t pcr_bank,
+ grub_uint16_t primary_alg,
+ const void *key_data,
+ grub_size_t key_data_size,
+ const void *policy_hash,
+ grub_size_t policy_hash_size,
+ void **ret_decrypted_key,
+ grub_size_t *ret_decrypted_key_size);
+
+#endif /* GRUB_SYSTEMD_TPM2_LUKS2_TPM2_HEADER */
diff --git a/grub-core/commands/tpm2_key_protector/module.c
b/grub-core/commands/tpm2_key_protector/module.c
index 857f3753f..553538861 100644
--- a/grub-core/commands/tpm2_key_protector/module.c
+++ b/grub-core/commands/tpm2_key_protector/module.c
@@ -24,13 +24,14 @@
#include <grub/misc.h>
#include <grub/mm.h>
#include <grub/key_protector.h>
+#include <grub/tpm2.h>
+#include <grub/tpm2srk.h>
#include <tss2_buffer.h>
#include <tss2_types.h>
#include <tss2_mu.h>
#include "tpm2_args.h"
-#include "tpm2.h"
#include "tpm2key.h"
GRUB_MOD_LICENSE ("GPLv3+");
@@ -400,170 +401,6 @@ tpm2_protector_unmarshal_tpm2key (void *sealed_key,
return err;
}
-/* Check if the SRK exists in the specified handle */
-static grub_err_t
-tpm2_protector_srk_check (const TPM_HANDLE_t srk_handle)
-{
- TPM_RC_t rc;
- TPM2B_PUBLIC_t public;
-
- /* Find SRK */
- rc = grub_tpm2_readpublic (srk_handle, NULL, &public);
- if (rc == TPM_RC_SUCCESS)
- return GRUB_ERR_NONE;
-
- return grub_error (GRUB_ERR_BAD_ARGUMENT, "failed to retrieve SRK
from 0x%x (TPM2_ReadPublic: 0x%x)", srk_handle, rc);
-}
-
-/* Get the SRK with the template */
-static grub_err_t
-tpm2_protector_srk_get (const grub_srk_type_t srk_type,
- const TPM_HANDLE_t parent,
- TPM_HANDLE_t *srk_handle)
-{
- TPM_RC_t rc;
- TPMT_PUBLIC_PARMS_t parms = {0};
- TPMS_AUTH_COMMAND_t authCommand = {0};
- TPM2B_SENSITIVE_CREATE_t inSensitive = {0};
- TPM2B_PUBLIC_t inPublic = {0};
- TPM2B_DATA_t outsideInfo = {0};
- TPML_PCR_SELECTION_t creationPcr = {0};
- TPM2B_PUBLIC_t outPublic = {0};
- TPM2B_CREATION_DATA_t creationData = {0};
- TPM2B_DIGEST_t creationHash = {0};
- TPMT_TK_CREATION_t creationTicket = {0};
- TPM2B_NAME_t srkName = {0};
- TPM_HANDLE_t tmp_handle = 0;
-
- inPublic.publicArea.type = 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;
-
- if (srk_type.type == 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 =
srk_type.detail.rsa_bits;
- inPublic.publicArea.parameters.rsaDetail.exponent = 0;
- }
- else if (srk_type.type == 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 =
srk_type.detail.ecc_curve;
- inPublic.publicArea.parameters.eccDetail.kdf.scheme = TPM_ALG_NULL;
- }
- else
- return grub_error (GRUB_ERR_BAD_ARGUMENT, "unknown SRK algorithm");
-
- /* Test the parameters before SRK generation */
- parms.type = srk_type.type;
- grub_memcpy (&parms.parameters, &inPublic.publicArea.parameters,
- sizeof (TPMU_PUBLIC_PARMS_t));
-
- rc = grub_tpm2_testparms (&parms, NULL);
- if (rc != TPM_RC_SUCCESS)
- return grub_error (GRUB_ERR_BAD_ARGUMENT, "unsupported SRK template
(TPM2_TestParms: 0x%x)", rc);
-
- /* Create SRK */
- authCommand.sessionHandle = TPM_RS_PW;
- rc = grub_tpm2_createprimary (parent, &authCommand, &inSensitive,
&inPublic,
- &outsideInfo, &creationPcr, &tmp_handle,
&outPublic,
- &creationData, &creationHash,
&creationTicket,
- &srkName, NULL);
- if (rc != TPM_RC_SUCCESS)
- return grub_error (GRUB_ERR_BAD_DEVICE, "could not create SRK
(TPM2_CreatePrimary: 0x%x)", rc);
-
- *srk_handle = tmp_handle;
-
- return GRUB_ERR_NONE;
-}
-
-/*
- * Load the SRK from the persistent handle or create one with a given
type of
- * template, and then associate the sealed key with the SRK
- * Return values:
- * - GRUB_ERR_NONE: Everything is fine.
- * - GRUB_ERR_BAD_ARGUMENT: The SRK doesn't match. Try another one.
- * - Other: Something went wrong.
- */
-static grub_err_t
-tpm2_protector_srk_load (const grub_srk_type_t srk_type,
- const tpm2_sealed_key_t *sealed_key,
- const TPM_HANDLE_t parent,
- TPM_HANDLE_t *sealed_handle,
- TPM_HANDLE_t *srk_handle)
-{
- TPMS_AUTH_COMMAND_t authCmd = {0};
- TPM2B_NAME_t name = {0};
- TPM_RC_t rc;
- grub_err_t err;
-
- if (srk_handle == NULL)
- return GRUB_ERR_BUG;
-
- if (*srk_handle != 0)
- {
- err = tpm2_protector_srk_check (*srk_handle);
- if (err != GRUB_ERR_NONE)
- return err;
- }
- else
- {
- err = tpm2_protector_srk_get (srk_type, parent, srk_handle);
- if (err != GRUB_ERR_NONE)
- return err;
- }
-
- /* Load the sealed key and associate it with the SRK */
- authCmd.sessionHandle = TPM_RS_PW;
- rc = grub_tpm2_load (*srk_handle, &authCmd, &sealed_key->private,
&sealed_key->public,
- sealed_handle, &name, NULL);
- /*
- * If TPM2_Load returns (TPM_RC_INTEGRITY | TPM_RC_P | TPM_RC_1), then it
- * implies the wrong SRK is used.
- */
- if (rc == (TPM_RC_INTEGRITY | TPM_RC_P | TPM_RC_1))
- {
- err = grub_error (GRUB_ERR_BAD_ARGUMENT, "SRK not matched");
- goto error;
- }
- else if (rc != TPM_RC_SUCCESS)
- {
- err = grub_error (GRUB_ERR_BAD_DEVICE, "failed to load sealed key
(TPM2_Load: 0x%x)", rc);
- goto error;
- }
-
- return GRUB_ERR_NONE;
-
- error:
- if (!TPM_HT_IS_PERSISTENT (*srk_handle))
- grub_tpm2_flushcontext (*srk_handle);
-
- return err;
-}
-
-static const char *
-srk_type_to_name (grub_srk_type_t srk_type)
-{
- if (srk_type.type == TPM_ALG_ECC && srk_type.detail.ecc_curve ==
TPM_ECC_NIST_P256)
- return "ECC_NIST_P256";
- else if (srk_type.type == TPM_ALG_RSA && srk_type.detail.rsa_bits ==
2048)
- return "RSA2048";
-
- return "Unknown";
-}
-
static grub_err_t
tpm2_protector_load_key (const tpm2_protector_context_t *ctx,
const tpm2_sealed_key_t *sealed_key,
@@ -577,10 +414,12 @@ tpm2_protector_load_key (const
tpm2_protector_context_t *ctx,
{
.type = TPM_ALG_ECC,
.detail.ecc_curve = TPM_ECC_NIST_P256,
+ .noDA = true,
},
{
.type = TPM_ALG_RSA,
.detail.rsa_bits = 2048,
+ .noDA = true,
},
{
.type = TPM_ALG_ERROR,
@@ -1022,6 +861,7 @@ tpm2_protector_key_from_buffer (const
tpm2_protector_context_t *ctx,
ctx_w = (tpm2_protector_context_t *)ctx;
ctx_w->srk_type.type = TPM_ALG_RSA;
ctx_w->srk_type.detail.rsa_bits = 2048;
+ ctx_w->srk_type.noDA = true;
}
}
else
@@ -1289,6 +1129,7 @@ tpm2_protector_check_args
(tpm2_protector_context_t *ctx)
{
ctx->srk_type.type = TPM_ALG_ECC;
ctx->srk_type.detail.ecc_curve = TPM_ECC_NIST_P256;
+ ctx->srk_type.noDA = true;
}
return GRUB_ERR_NONE;
diff --git a/grub-core/commands/tpm2_key_protector/tpm2_args.h
b/grub-core/commands/tpm2_key_protector/tpm2_args.h
index bdbf9f373..805e293f0 100644
--- a/grub-core/commands/tpm2_key_protector/tpm2_args.h
+++ b/grub-core/commands/tpm2_key_protector/tpm2_args.h
@@ -21,18 +21,7 @@
#define GRUB_TPM2_INTERNAL_ARGS_HEADER 1
#include <grub/err.h>
-
-#include "tpm2.h"
-
-struct grub_srk_type
-{
- TPMI_ALG_PUBLIC_t type;
- union {
- TPM_KEY_BITS_t rsa_bits;
- TPM_ECC_CURVE_t ecc_curve;
- } detail;
-};
-typedef struct grub_srk_type grub_srk_type_t;
+#include <grub/tpm2.h>
extern grub_err_t
grub_tpm2_protector_parse_pcrs (char *value, grub_uint8_t *pcrs,
grub_uint8_t *pcr_count);
diff --git a/grub-core/disk/luks2.c b/grub-core/disk/luks2.c
index 8036d76ff..3e0894320 100644
--- a/grub-core/disk/luks2.c
+++ b/grub-core/disk/luks2.c
@@ -28,6 +28,8 @@
#include <grub/i18n.h>
#include <grub/safemath.h>
+#include <grub/luks2.h>
+
#include <base64.h>
#include <json.h>
@@ -36,12 +38,8 @@ GRUB_MOD_LICENSE ("GPLv3+");
#define LUKS_MAGIC_1ST "LUKS\xBA\xBE"
#define LUKS_MAGIC_2ND "SKUL\xBA\xBE"
-enum grub_luks2_kdf_type
-{
- LUKS2_KDF_TYPE_ARGON2I,
- LUKS2_KDF_TYPE_PBKDF2
-};
-typedef enum grub_luks2_kdf_type grub_luks2_kdf_type_t;
+/* From tss2_types.h */
+#define TPM_MAX_PCRS 24
/* On disk LUKS header */
struct grub_luks2_header
@@ -62,69 +60,6 @@ struct grub_luks2_header
} GRUB_PACKED;
typedef struct grub_luks2_header grub_luks2_header_t;
-struct grub_luks2_keyslot
-{
- /* The integer key to the associative array of keyslots. */
- grub_uint64_t idx;
- grub_int64_t key_size;
- grub_int64_t priority;
- struct
- {
- const char *encryption;
- grub_uint64_t offset;
- grub_uint64_t size;
- grub_int64_t key_size;
- } area;
- struct
- {
- const char *hash;
- grub_int64_t stripes;
- } af;
- struct
- {
- grub_luks2_kdf_type_t type;
- const char *salt;
- union
- {
- struct
- {
- grub_int64_t time;
- grub_int64_t memory;
- grub_int64_t cpus;
- } argon2i;
- struct
- {
- const char *hash;
- grub_int64_t iterations;
- } pbkdf2;
- } u;
- } kdf;
-};
-typedef struct grub_luks2_keyslot grub_luks2_keyslot_t;
-
-struct grub_luks2_segment
-{
- grub_uint64_t idx;
- grub_uint64_t offset;
- const char *size;
- const char *encryption;
- grub_int64_t sector_size;
-};
-typedef struct grub_luks2_segment grub_luks2_segment_t;
-
-struct grub_luks2_digest
-{
- grub_uint64_t idx;
- /* Both keyslots and segments are interpreted as bitfields here */
- grub_uint64_t keyslots;
- grub_uint64_t segments;
- const char *salt;
- const char *digest;
- const char *hash;
- grub_int64_t iterations;
-};
-typedef struct grub_luks2_digest grub_luks2_digest_t;
-
gcry_err_code_t AF_merge (const gcry_md_spec_t * hash, grub_uint8_t * src,
grub_uint8_t * dst, grub_size_t blocksize,
grub_size_t blocknumbers);
@@ -258,11 +193,78 @@ luks2_parse_digest (grub_luks2_digest_t *out,
const grub_json_t *digest)
return GRUB_ERR_NONE;
}
+static grub_err_t
+luks2_parse_token (grub_luks2_token_t *out, const grub_json_t *token)
+{
+ grub_json_t keyslots, pcrs, o;
+ grub_size_t i, size;
+ grub_uint64_t bit;
+ const char *type;
+ const char *pcr_bank;
+ const char *alg;
+
+ if (grub_json_getstring (&type, token, "type"))
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid digest type");
+ else if (grub_strcmp (type, "systemd-tpm2"))
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Unsupported digest type
%s", type);
+ out->type = LUKS2_TOKEN_TYPE_SYSTEMD_TPM2;
+
+ if (grub_json_getvalue (&keyslots, token, "keyslots") ||
+ grub_json_getvalue (&pcrs, token, "tpm2-pcrs") ||
+ grub_json_getstring (&pcr_bank, token, "tpm2-pcr-bank") ||
+ grub_json_getstring (&alg, token, "tpm2-primary-alg") ||
+ grub_json_getstring (&out->u.systemd_tpm2.base64_blob, token,
"tpm2-blob") ||
+ grub_json_getstring (&out->u.systemd_tpm2.hex_policy_hash, token,
"tpm2-policy-hash"))
+ {
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Missing token parameters");
+ }
+
+ if (grub_json_getsize (&size, &pcrs))
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "token references no pcrs");
+
+ out->u.systemd_tpm2.pcr_mask = 0;
+ for (i = 0; i < size; i++)
+ {
+ if (grub_json_getchild (&o, &pcrs, i) ||
+ grub_json_getuint64 (&bit, &o, NULL) || bit >= TPM_MAX_PCRS)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid pcr");
+ out->u.systemd_tpm2.pcr_mask |= (1 << bit);
+ }
+
+ if (grub_strcmp (pcr_bank, "sha256") == 0)
+ out->u.systemd_tpm2.pcr_bank =
LUKS2_TOKEN_SYSTEMD_TPM2_PCR_BANK_TYPE_SHA256;
+ else if (grub_strcmp (pcr_bank, "sha1") == 0)
+ out->u.systemd_tpm2.pcr_bank =
LUKS2_TOKEN_SYSTEMD_TPM2_PCR_BANK_TYPE_SHA1;
+ else
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Unsupported pcr-bank
type %s", pcr_bank);
+
+ if (grub_strcmp (alg, "ecc") == 0)
+ out->u.systemd_tpm2.primary_alg =
LUKS2_TOKEN_SYSTEMD_TPM2_ALGO_TYPE_ECC;
+ else if (grub_strcmp (alg, "rsa") == 0)
+ out->u.systemd_tpm2.primary_alg =
LUKS2_TOKEN_SYSTEMD_TPM2_ALGO_TYPE_RSA;
+ else
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Unsupported algo type
%s", alg);
+
+ if (grub_json_getsize (&size, &keyslots))
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "token references no
keyslots");
+
+ out->keyslots = 0;
+ for (i = 0; i < size; i++)
+ {
+ if (grub_json_getchild (&o, &keyslots, i) ||
+ grub_json_getuint64 (&bit, &o, NULL))
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid keyslot");
+ out->keyslots |= (1 << bit);
+ }
+
+ return GRUB_ERR_NONE;
+}
+
static grub_err_t
luks2_get_keyslot (grub_luks2_keyslot_t *k, grub_luks2_digest_t *d,
grub_luks2_segment_t *s,
- const grub_json_t *root, grub_size_t keyslot_json_idx)
+ grub_luks2_token_t *t, const grub_json_t *root, grub_size_t
keyslot_json_idx)
{
- grub_json_t keyslots, keyslot, digests, digest, segments, segment;
+ grub_json_t keyslots, keyslot, digests, digest, segments, segment,
tokens, token;
grub_size_t json_idx, size;
/* Get nth keyslot */
@@ -309,6 +311,27 @@ luks2_get_keyslot (grub_luks2_keyslot_t *k,
grub_luks2_digest_t *d, grub_luks2_s
if (json_idx == size)
return grub_error (GRUB_ERR_FILE_NOT_FOUND, "No segment for digest
\"%" PRIuGRUB_UINT64_T "\"", d->idx);
+ if (t == NULL)
+ return GRUB_ERR_NONE;
+
+ /* Get token that matches the keyslot. */
+ if (grub_json_getvalue (&tokens, root, "tokens") ||
+ grub_json_getsize (&size, &tokens))
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Could not get tokens");
+ for (json_idx = 0; json_idx < size; json_idx++)
+ {
+ if (grub_json_getchild (&token, &tokens, json_idx) ||
+ grub_json_getuint64 (&t->idx, &token, NULL) ||
+ grub_json_getchild (&token, &token, 0) ||
+ luks2_parse_token (t, &token))
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Could not parse token
index %" PRIuGRUB_SIZE, json_idx);
+
+ if ((t->keyslots & (1 << k->idx)))
+ break;
+ }
+ if (json_idx == size)
+ return grub_error (GRUB_ERR_FILE_NOT_FOUND, "No token for keyslot
\"%" PRIuGRUB_UINT64_T "\"", k->idx);
+
return GRUB_ERR_NONE;
}
@@ -555,6 +578,91 @@ luks2_decrypt_key (grub_uint8_t *out_key,
return ret;
}
+extern grub_err_t
+luks2_iterate_keyslot(grub_disk_t source, grub_uint32_t flags,
luks2_iterate_fct_t fct)
+{
+ char *json_header = NULL, *ptr;
+ grub_size_t json_idx, size;
+ grub_luks2_header_t header;
+ grub_luks2_keyslot_t keyslot;
+ grub_luks2_digest_t digest;
+ grub_luks2_segment_t segment;
+ grub_luks2_token_t token;
+ grub_json_t *json = NULL, keyslots;
+ grub_err_t ret;
+ grub_size_t sz;
+
+ ret = luks2_read_header (source, &header);
+ if (ret)
+ return ret;
+
+ if (grub_sub (grub_be_to_cpu64 (header.hdr_size), sizeof (header), &sz))
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, "underflow detected while
calculating json header size");
+
+ json_header = grub_zalloc (sz);
+ if (!json_header)
+ return GRUB_ERR_OUT_OF_MEMORY;
+
+ /* Read the JSON area. */
+ ret = grub_disk_read (source, 0, grub_be_to_cpu64 (header.hdr_offset)
+ sizeof (header),
+ grub_be_to_cpu64 (header.hdr_size) - sizeof
(header), json_header);
+ if (ret)
+ goto err;
+
+ ptr = grub_memchr (json_header, 0, grub_be_to_cpu64 (header.hdr_size)
- sizeof (header));
+ if (!ptr)
+ goto err;
+
+ ret = grub_json_parse (&json, json_header, grub_be_to_cpu64
(header.hdr_size));
+ if (ret)
+ {
+ ret = grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid LUKS2 JSON
header");
+ goto err;
+ }
+
+ if (grub_json_getvalue (&keyslots, json, "keyslots") ||
+ grub_json_getsize (&size, &keyslots))
+ {
+ ret = grub_error (GRUB_ERR_BAD_ARGUMENT, "Could not get keyslots");
+ goto err;
+ }
+
+ if (grub_disk_native_sectors (source) == GRUB_DISK_SIZE_UNKNOWN)
+ {
+ /* FIXME: Allow use of source disk, and maybe cause errors in
read. */
+ grub_dprintf ("luks2", "Source disk %s has an unknown size, "
+ "conservatively returning error\n",
source->name);
+ ret = grub_error (GRUB_ERR_BUG, "Unknown size of luks2 source
device");
+ goto err;
+ }
+
+ /* Try all keyslot */
+ for (json_idx = 0; json_idx < size; json_idx++)
+ {
+ grub_errno = GRUB_ERR_NONE;
+ ret = luks2_get_keyslot (&keyslot, &digest, &segment, (flags &
LUKS2_ITERATE_FLAGS_WITH_TOKEN) ? &token: NULL, json, json_idx);
+ if (ret)
+ {
+ /*
+ * luks2_get_keyslot() can fail for a variety of reasons that
do not
+ * necessarily mean the next keyslot should not be tried (e.g.
a new
+ * kdf type). So always try the next slot.
+ */
+ grub_dprintf ("luks2", "Failed to get keyslot %"
PRIuGRUB_UINT64_T "\n", keyslot.idx);
+ continue;
+ }
+ if (grub_errno != GRUB_ERR_NONE)
+ grub_dprintf ("luks2", "Ignoring unhandled error %d from
luks2_get_keyslot\n", grub_errno);
+
+
+ fct(&keyslot, &digest, &segment, (flags &
LUKS2_ITERATE_FLAGS_WITH_TOKEN) ? &token: NULL);
+ }
+err:
+ grub_free (json_header);
+ grub_json_free (json);
+ return ret;
+}
+
static grub_err_t
luks2_recover_key (grub_disk_t source,
grub_cryptodisk_t crypt,
@@ -626,7 +734,7 @@ luks2_recover_key (grub_disk_t source,
typeof (source->total_sectors) max_crypt_sectors = 0;
grub_errno = GRUB_ERR_NONE;
- ret = luks2_get_keyslot (&keyslot, &digest, &segment, json,
json_idx);
+ ret = luks2_get_keyslot (&keyslot, &digest, &segment, NULL, json,
json_idx);
if (ret)
{
/*
diff --git a/grub-core/lib/base64.c b/grub-core/lib/base64.c
new file mode 100644
index 000000000..b12668fad
--- /dev/null
+++ b/grub-core/lib/base64.c
@@ -0,0 +1,21 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * 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 <grub/dl.h>
+
+GRUB_MOD_LICENSE ("GPLv2+");
\ No newline at end of file
diff --git a/grub-core/lib/tpm2srk.c b/grub-core/lib/tpm2srk.c
new file mode 100644
index 000000000..3c1e4f7dc
--- /dev/null
+++ b/grub-core/lib/tpm2srk.c
@@ -0,0 +1,191 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2022 Microsoft Corporation
+ * 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 <grub/tpm2srk.h>
+
+#include <grub/dl.h>
+#include <grub/misc.h>
+#include <grub/types.h>
+#include <stddef.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+/* Check if the SRK exists in the specified handle */
+grub_err_t
+tpm2_protector_srk_check (const TPM_HANDLE_t srk_handle)
+{
+ TPM_RC_t rc;
+ TPM2B_PUBLIC_t public;
+
+ /* Find SRK */
+ rc = grub_tpm2_readpublic (srk_handle, NULL, &public);
+ if (rc == TPM_RC_SUCCESS)
+ return GRUB_ERR_NONE;
+
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "failed to retrieve SRK
from 0x%x (TPM2_ReadPublic: 0x%x)", srk_handle, rc);
+}
+
+/* Get the SRK with the template */
+grub_err_t
+tpm2_protector_srk_get (const grub_srk_type_t srk_type,
+ const TPM_HANDLE_t parent,
+ TPM_HANDLE_t *srk_handle)
+{
+ TPM_RC_t rc;
+ TPMT_PUBLIC_PARMS_t parms = {0};
+ TPMS_AUTH_COMMAND_t authCommand = {0};
+ TPM2B_SENSITIVE_CREATE_t inSensitive = {0};
+ TPM2B_PUBLIC_t inPublic = {0};
+ TPM2B_DATA_t outsideInfo = {0};
+ TPML_PCR_SELECTION_t creationPcr = {0};
+ TPM2B_PUBLIC_t outPublic = {0};
+ TPM2B_CREATION_DATA_t creationData = {0};
+ TPM2B_DIGEST_t creationHash = {0};
+ TPMT_TK_CREATION_t creationTicket = {0};
+ TPM2B_NAME_t srkName = {0};
+ TPM_HANDLE_t tmp_handle = 0;
+
+ inPublic.publicArea.type = 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 = srk_type.noDA;
+
+ if (srk_type.type == 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 =
srk_type.detail.rsa_bits;
+ inPublic.publicArea.parameters.rsaDetail.exponent = 0;
+ }
+ else if (srk_type.type == 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 =
srk_type.detail.ecc_curve;
+ inPublic.publicArea.parameters.eccDetail.kdf.scheme = TPM_ALG_NULL;
+ }
+ else
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "unknown SRK algorithm");
+
+ /* Test the parameters before SRK generation */
+ parms.type = srk_type.type;
+ grub_memcpy (&parms.parameters, &inPublic.publicArea.parameters,
+ sizeof (TPMU_PUBLIC_PARMS_t));
+
+ rc = grub_tpm2_testparms (&parms, NULL);
+ if (rc != TPM_RC_SUCCESS)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "unsupported SRK template
(TPM2_TestParms: 0x%x)", rc);
+
+ /* Create SRK */
+ authCommand.sessionHandle = TPM_RS_PW;
+ rc = grub_tpm2_createprimary (parent, &authCommand, &inSensitive,
&inPublic,
+ &outsideInfo, &creationPcr, &tmp_handle,
&outPublic,
+ &creationData, &creationHash,
&creationTicket,
+ &srkName, NULL);
+ if (rc != TPM_RC_SUCCESS)
+ return grub_error (GRUB_ERR_BAD_DEVICE, "could not create SRK
(TPM2_CreatePrimary: 0x%x)", rc);
+
+ *srk_handle = tmp_handle;
+
+ return GRUB_ERR_NONE;
+}
+
+/*
+ * Load the SRK from the persistent handle or create one with a given
type of
+ * template, and then associate the sealed key with the SRK
+ * Return values:
+ * - GRUB_ERR_NONE: Everything is fine.
+ * - GRUB_ERR_BAD_ARGUMENT: The SRK doesn't match. Try another one.
+ * - Other: Something went wrong.
+ */
+grub_err_t
+tpm2_protector_srk_load (const grub_srk_type_t srk_type,
+ const tpm2_sealed_key_t *sealed_key,
+ const TPM_HANDLE_t parent,
+ TPM_HANDLE_t *sealed_handle,
+ TPM_HANDLE_t *srk_handle)
+{
+ TPMS_AUTH_COMMAND_t authCmd = {0};
+ TPM2B_NAME_t name = {0};
+ TPM_RC_t rc;
+ grub_err_t err;
+
+ if (srk_handle == NULL)
+ return GRUB_ERR_BUG;
+
+ if (*srk_handle != 0)
+ {
+ err = tpm2_protector_srk_check (*srk_handle);
+ if (err != GRUB_ERR_NONE)
+ return err;
+ }
+ else
+ {
+ err = tpm2_protector_srk_get (srk_type, parent, srk_handle);
+ if (err != GRUB_ERR_NONE)
+ return err;
+ }
+
+ /* Load the sealed key and associate it with the SRK */
+ authCmd.sessionHandle = TPM_RS_PW;
+ rc = grub_tpm2_load (*srk_handle, &authCmd, &sealed_key->private,
&sealed_key->public,
+ sealed_handle, &name, NULL);
+ /*
+ * If TPM2_Load returns (TPM_RC_INTEGRITY | TPM_RC_P | TPM_RC_1), then it
+ * implies the wrong SRK is used.
+ */
+ if (rc == (TPM_RC_INTEGRITY | TPM_RC_P | TPM_RC_1))
+ {
+ err = grub_error (GRUB_ERR_BAD_ARGUMENT, "SRK not matched");
+ goto error;
+ }
+ else if (rc != TPM_RC_SUCCESS)
+ {
+ err = grub_error (GRUB_ERR_BAD_DEVICE, "failed to load sealed key
(TPM2_Load: 0x%x)", rc);
+ goto error;
+ }
+
+ return GRUB_ERR_NONE;
+
+ error:
+ if (!TPM_HT_IS_PERSISTENT (*srk_handle))
+ grub_tpm2_flushcontext (*srk_handle);
+
+ return err;
+}
+
+const char *
+srk_type_to_name (grub_srk_type_t srk_type)
+{
+ if (srk_type.type == TPM_ALG_ECC && srk_type.detail.ecc_curve ==
TPM_ECC_NIST_P256)
+ return "ECC_NIST_P256";
+ else if (srk_type.type == TPM_ALG_RSA && srk_type.detail.rsa_bits ==
2048)
+ return "RSA2048";
+
+ return "Unknown";
+}
\ No newline at end of file
diff --git a/include/grub/luks2.h b/include/grub/luks2.h
new file mode 100644
index 000000000..494307398
--- /dev/null
+++ b/include/grub/luks2.h
@@ -0,0 +1,148 @@
+/* luks2.h - On disk structures for LUKS2. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2006,2007 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/>.
+ */
+
+#ifndef GRUB_LUKS2_H
+#define GRUB_LUKS2_H 1
+
+#include <grub/disk.h>
+#include <grub/err.h>
+
+enum grub_luks2_kdf_type
+{
+ LUKS2_KDF_TYPE_ARGON2I,
+ LUKS2_KDF_TYPE_PBKDF2
+};
+typedef enum grub_luks2_kdf_type grub_luks2_kdf_type_t;
+
+struct grub_luks2_keyslot
+{
+ /* The integer key to the associative array of keyslots. */
+ grub_uint64_t idx;
+ grub_int64_t key_size;
+ grub_int64_t priority;
+ struct
+ {
+ const char *encryption;
+ grub_uint64_t offset;
+ grub_uint64_t size;
+ grub_int64_t key_size;
+ } area;
+ struct
+ {
+ const char *hash;
+ grub_int64_t stripes;
+ } af;
+ struct
+ {
+ grub_luks2_kdf_type_t type;
+ const char *salt;
+ union
+ {
+ struct
+ {
+ grub_int64_t time;
+ grub_int64_t memory;
+ grub_int64_t cpus;
+ } argon2i;
+ struct
+ {
+ const char *hash;
+ grub_int64_t iterations;
+ } pbkdf2;
+ } u;
+ } kdf;
+};
+typedef struct grub_luks2_keyslot grub_luks2_keyslot_t;
+
+struct grub_luks2_segment
+{
+ grub_uint64_t idx;
+ grub_uint64_t offset;
+ const char *size;
+ const char *encryption;
+ grub_int64_t sector_size;
+};
+typedef struct grub_luks2_segment grub_luks2_segment_t;
+
+struct grub_luks2_digest
+{
+ grub_uint64_t idx;
+ /* Both keyslots and segments are interpreted as bitfields here */
+ grub_uint64_t keyslots;
+ grub_uint64_t segments;
+ const char *salt;
+ const char *digest;
+ const char *hash;
+ grub_int64_t iterations;
+};
+typedef struct grub_luks2_digest grub_luks2_digest_t;
+
+
+enum grub_luks2_token_type
+{
+ LUKS2_TOKEN_TYPE_NONE,
+ LUKS2_TOKEN_TYPE_SYSTEMD_TPM2
+};
+
+typedef enum grub_luks2_token_type grub_luks2_token_type_t;
+
+enum grub_luks2_token_systemd_tpm2_algo_type
+{
+ LUKS2_TOKEN_SYSTEMD_TPM2_ALGO_TYPE_ECC,
+ LUKS2_TOKEN_SYSTEMD_TPM2_ALGO_TYPE_RSA
+};
+
+typedef enum grub_luks2_token_systemd_tpm2_algo_type
grub_luks2_token_systemd_tpm2_algo_type_t;
+
+enum grub_luks2_token_systemd_tpm2_pcr_bank_type
+{
+ LUKS2_TOKEN_SYSTEMD_TPM2_PCR_BANK_TYPE_SHA256,
+ LUKS2_TOKEN_SYSTEMD_TPM2_PCR_BANK_TYPE_SHA1
+};
+
+typedef enum grub_luks2_token_systemd_tpm2_pcr_bank_type
grub_luks2_token_systemd_tpm2_pcr_bank_type_t;
+
+struct grub_luks2_token
+{
+ grub_uint64_t idx;
+ grub_luks2_token_type_t type;
+ grub_uint64_t keyslots;
+ union
+ {
+ struct
+ {
+ grub_uint32_t pcr_mask;
+ grub_luks2_token_systemd_tpm2_pcr_bank_type_t pcr_bank;
+ grub_luks2_token_systemd_tpm2_algo_type_t primary_alg;
+ const char *base64_blob;
+ const char *hex_policy_hash;
+ } systemd_tpm2;
+ } u;
+};
+typedef struct grub_luks2_token grub_luks2_token_t;
+
+typedef void (*luks2_iterate_fct_t)(grub_luks2_keyslot_t *k,
grub_luks2_digest_t *d, grub_luks2_segment_t *s, grub_luks2_token_t *t);
+
+#define LUKS2_ITERATE_FLAGS_NONE 0
+#define LUKS2_ITERATE_FLAGS_WITH_TOKEN 1 << 0
+
+extern grub_err_t
+luks2_iterate_keyslot(grub_disk_t source, grub_uint32_t flags,
luks2_iterate_fct_t fct);
+
+#endif /* ! GRUB_LUKS2_H */
\ No newline at end of file
diff --git a/grub-core/commands/tpm2_key_protector/tpm2.h
b/include/grub/tpm2.h
similarity index 85%
rename from grub-core/commands/tpm2_key_protector/tpm2.h
rename to include/grub/tpm2.h
index 1c1d871b4..1e25a9bdd 100644
--- a/grub-core/commands/tpm2_key_protector/tpm2.h
+++ b/include/grub/tpm2.h
@@ -33,4 +33,15 @@ struct tpm2_sealed_key {
};
typedef struct tpm2_sealed_key tpm2_sealed_key_t;
+struct grub_srk_type
+{
+ TPMI_ALG_PUBLIC_t type;
+ union {
+ TPM_KEY_BITS_t rsa_bits;
+ TPM_ECC_CURVE_t ecc_curve;
+ } detail;
+ bool noDA;
+};
+typedef struct grub_srk_type grub_srk_type_t;
+
#endif /* ! GRUB_TPM2_TPM2_HEADER */
diff --git a/include/grub/tpm2srk.h b/include/grub/tpm2srk.h
new file mode 100644
index 000000000..684d89bba
--- /dev/null
+++ b/include/grub/tpm2srk.h
@@ -0,0 +1,44 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2022 Microsoft Corporation
+ * 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/>.
+ */
+
+#ifndef GRUB_TPM2_INTERNAL_SRK_HEADER
+#define GRUB_TPM2_INTERNAL_SRK_HEADER 1
+
+#include <grub/err.h>
+#include <grub/tpm2.h>
+
+grub_err_t
+tpm2_protector_srk_check (const TPM_HANDLE_t srk_handle);
+
+grub_err_t
+tpm2_protector_srk_get (const grub_srk_type_t srk_type,
+ const TPM_HANDLE_t parent,
+ TPM_HANDLE_t *srk_handle);
+
+grub_err_t
+tpm2_protector_srk_load (const grub_srk_type_t srk_type,
+ const tpm2_sealed_key_t *sealed_key,
+ const TPM_HANDLE_t parent,
+ TPM_HANDLE_t *sealed_handle,
+ TPM_HANDLE_t *srk_handle);
+
+const char *
+srk_type_to_name (grub_srk_type_t srk_type);
+
+#endif //GRUB_TPM2_INTERNAL_SRK_HEADER
diff --git a/util/grub-protect.c b/util/grub-protect.c
index 40d4a3fc5..c565daf5e 100644
--- a/util/grub-protect.c
+++ b/util/grub-protect.c
@@ -31,12 +31,14 @@
#include <grub/emu/misc.h>
#include <grub/util/misc.h>
+#include <grub/tpm2.h>
+#include <grub/tpm2srk.h>
#include <tss2_buffer.h>
#include <tss2_mu.h>
#include <tcg2.h>
#include <tpm2_args.h>
-#include <tpm2.h>
+#include <base64.h>
#pragma GCC diagnostic ignored "-Wmissing-prototypes"
#pragma GCC diagnostic ignored "-Wmissing-declarations"
@@ -534,18 +536,10 @@ protect_tpm2_get_policy_digest (protect_args_t
*args, TPM2B_DIGEST_t *digest)
static grub_err_t
protect_tpm2_get_srk (protect_args_t *args, TPM_HANDLE_t *srk)
{
+ grub_err_t ret;
TPM_RC_t rc;
TPM2B_PUBLIC_t public;
TPMS_AUTH_COMMAND_t authCommand = {0};
- TPM2B_SENSITIVE_CREATE_t inSensitive = {0};
- TPM2B_PUBLIC_t inPublic = {0};
- TPM2B_DATA_t outsideInfo = {0};
- TPML_PCR_SELECTION_t creationPcr = {0};
- TPM2B_PUBLIC_t outPublic = {0};
- TPM2B_CREATION_DATA_t creationData = {0};
- TPM2B_DIGEST_t creationHash = {0};
- TPMT_TK_CREATION_t creationTicket = {0};
- TPM2B_NAME_t srkName = {0};
TPM_HANDLE_t srkHandle;
if (args->tpm2_srk != 0)
@@ -567,50 +561,11 @@ protect_tpm2_get_srk (protect_args_t *args,
TPM_HANDLE_t *srk)
}
}
- /* 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;
- 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 =
args->srk_type.detail.ecc_curve;
- inPublic.publicArea.parameters.eccDetail.kdf.scheme = TPM_ALG_NULL;
- break;
-
- default:
- return GRUB_ERR_BAD_ARGUMENT;
- }
-
- rc = grub_tpm2_createprimary (TPM_RH_OWNER, &authCommand,
&inSensitive, &inPublic,
- &outsideInfo, &creationPcr, &srkHandle,
&outPublic,
- &creationData, &creationHash,
&creationTicket,
- &srkName, NULL);
- if (rc != TPM_RC_SUCCESS)
+ ret = tpm2_protector_srk_get(args->srk_type, TPM_RH_OWNER, &srkHandle);
+ if (ret != GRUB_ERR_NONE)
{
- fprintf (stderr, "Failed to create SRK (TPM2_CreatePrimary:
0x%x).\n", rc);
- return GRUB_ERR_BAD_DEVICE;
+ return ret;
}
/* Persist SRK */
@@ -1274,6 +1229,7 @@ protect_tpm2_args_verify (protect_args_t *args)
{
args->srk_type.type = TPM_ALG_ECC;
args->srk_type.detail.ecc_curve = TPM_ECC_NIST_P256;
+ args->srk_type.noDA = true;
}
if (args->tpm2_bank == TPM_ALG_ERROR)
--
2.39.5
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel