Enroll your TPM2 device by creating a token inside LUKS2 header: systemd-cryptenroll /dev/sdXY --tpm2-device=auto
Then, in the boot script: tpm2_key_protector_init --device=hdX,gptY cryptomount hdX,gptY -P systemd-tpm2 The arguments --keyslot=i and/or --token=j can be used to filter which token to use. Supports trusted srk (tpm2_srk field) introduced in systemd v254. Signed-off-by: Yann Diorcet <diorcet.y...@gmail.com> --- grub-core/Makefile.core.def | 3 +- .../commands/tpm2_key_protector/module.c | 308 +++++++++++++++++- .../commands/tpm2_key_protector/tpm2_luks2.c | 280 ++++++++++++++++ .../commands/tpm2_key_protector/tpm2_luks2.h | 39 +++ 4 files changed, 626 insertions(+), 4 deletions(-) create mode 100644 grub-core/commands/tpm2_key_protector/tpm2_luks2.c create mode 100644 grub-core/commands/tpm2_key_protector/tpm2_luks2.h diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index 0dfe85ab6..219a96966 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -2585,10 +2585,11 @@ module = { common = commands/tpm2_key_protector/tpm2key.c; common = commands/tpm2_key_protector/tpm2key_asn1_tab.c; common = commands/tpm2_key_protector/tpm2srk.c; + common = commands/tpm2_key_protector/tpm2_luks2.c; /* The plaform support of tpm2_key_protector depends on the tcg2 implementation in tss2. */ enable = efi; enable = emu; - cppflags = '-I$(srcdir)/lib/tss2 -I$(srcdir)/lib/libtasn1-grub'; + cppflags = '$(CPPFLAGS_GNULIB) -I$(srcdir)/lib/tss2 -I$(srcdir)/lib/libtasn1-grub'; }; module = { diff --git a/grub-core/commands/tpm2_key_protector/module.c b/grub-core/commands/tpm2_key_protector/module.c index 4f7b6e95d..60f45efa6 100644 --- a/grub-core/commands/tpm2_key_protector/module.c +++ b/grub-core/commands/tpm2_key_protector/module.c @@ -24,6 +24,8 @@ #include <grub/misc.h> #include <grub/mm.h> #include <grub/key_protector.h> +#include <grub/luks2.h> +#include <base64.h> #include <tss2_buffer.h> #include <tss2_types.h> @@ -32,6 +34,7 @@ #include "tpm2_args.h" #include "tpm2.h" #include "tpm2key.h" +#include "tpm2_luks2.h" GRUB_MOD_LICENSE ("GPLv3+"); @@ -39,7 +42,8 @@ typedef enum tpm2_protector_mode { TPM2_PROTECTOR_MODE_UNSET, TPM2_PROTECTOR_MODE_SRK, - TPM2_PROTECTOR_MODE_NV + TPM2_PROTECTOR_MODE_NV, + TPM2_PROTECTOR_MODE_LUKS2_TOKEN, } tpm2_protector_mode_t; typedef enum tpm2_protector_options @@ -51,7 +55,10 @@ typedef enum tpm2_protector_options OPTION_KEYFILE, OPTION_SRK, OPTION_ASYMMETRIC, - OPTION_NVINDEX + OPTION_NVINDEX, + OPTION_DEVICE, + OPTION_KEYSLOT, + OPTION_TOKEN, } tpm2_protector_options_t; typedef struct tpm2_protector_context @@ -65,6 +72,9 @@ typedef struct tpm2_protector_context const char *keyfile; TPM_HANDLE_t srk; TPM_HANDLE_t nv; + grub_int8_t keyslot_idx; + grub_int8_t token_idx; + grub_luks2_token_t token; } tpm2_protector_context_t; static const struct grub_arg_option tpm2_protector_init_cmd_options[] = @@ -152,6 +162,30 @@ static const struct grub_arg_option tpm2_protector_init_cmd_options[] = N_("Required in NV Index mode, the NV handle to read which must " "readily exist on the TPM and which contains the key."), }, + { + .longarg = "device", + .shortarg = 'd', + .flags = 0, + .arg = NULL, + .type = ARG_TYPE_STRING, + .doc = N_("Use this LUKS partition looking for token to use"), + }, + { + .longarg = "keyslot", + .shortarg = 'K', + .flags = 0, + .arg = NULL, + .type = ARG_TYPE_INT, + .doc = N_("Set the keyslot index to use in the LUKS partition"), + }, + { + .longarg = "token", + .shortarg = 't', + .flags = 0, + .arg = NULL, + .type = ARG_TYPE_INT, + .doc = N_("Set the token index to use in the LUKS partition"), + }, /* End of list */ {0, 0, 0, 0, 0, 0} }; @@ -1046,6 +1080,173 @@ tpm2_protector_nv_recover (const tpm2_protector_context_t *ctx, return err; } +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, grub_size_t l, void **ret, grub_size_t *ret_len) { + char *buf = NULL; + grub_size_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 == GRUB_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 = (grub_size_t) (z - buf); + *ret = buf; + + return r; + +on_failure: + grub_free(buf); + *ret = NULL; + *ret_len = 0; + + return r; +} + +static grub_err_t +tpm2_protector_luks2_token_recover (const tpm2_protector_context_t *ctx, + 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; + grub_size_t base64_encode_size; + + const char *hex_hash; + char *policy_hash; + grub_size_t policy_hash_size; + + const char *base64_srk; + char *srk = NULL; + idx_t srk_size = 0; + + grub_err_t ret = GRUB_ERR_NONE; + + if (key == NULL || key_size == NULL) + return GRUB_ERR_BAD_ARGUMENT; + + base64_blob = 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 = 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; + } + + base64_srk = ctx->token.u.systemd_tpm2.base64_srk; + if (base64_srk != NULL) + { + if(base64_decode_alloc(base64_srk, grub_strlen (base64_srk), &srk, &srk_size) == 0) + { + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Can't decode base64 srk")); + } + } + + ret = tpm2_luks2_acquire_luks2_key( + ctx->token.u.systemd_tpm2.pcr_mask, + ctx->token.u.systemd_tpm2.pcr_bank, + ctx->token.u.systemd_tpm2.primary_alg, + blob, + blob_size, + policy_hash, + policy_hash_size, + srk, + srk_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_recover (const tpm2_protector_context_t *ctx, grub_uint8_t **key, grub_size_t *key_size) @@ -1056,6 +1257,8 @@ tpm2_protector_recover (const tpm2_protector_context_t *ctx, return tpm2_protector_srk_recover (ctx, key, key_size); case TPM2_PROTECTOR_MODE_NV: return tpm2_protector_nv_recover (ctx, key, key_size); + case TPM2_PROTECTOR_MODE_LUKS2_TOKEN: + return tpm2_protector_luks2_token_recover (ctx, key, key_size); default: return GRUB_ERR_BAD_ARGUMENT; } @@ -1160,18 +1363,68 @@ tpm2_protector_parse_mode (const char *value, tpm2_protector_mode_t *mode) return GRUB_ERR_NONE; } +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, + grub_luks2_digest_t *d __attribute__ ((unused)), + grub_luks2_segment_t *s __attribute__ ((unused)), + grub_luks2_token_t *t) +{ + if (tpm2_protector_ctx.keyslot_idx >= 0 && k->idx != (grub_uint64_t)tpm2_protector_ctx.keyslot_idx) + return; + if (tpm2_protector_ctx.token_idx >= 0 && t->idx != (grub_uint64_t)tpm2_protector_ctx.token_idx) + return; + + if (tpm2_protector_ctx.token.type != LUKS2_TOKEN_TYPE_NONE) + { + grub_printf ("systemd-tpm2 already set: multiple keyslots matched. Ignoring the token %ld\n", t->idx); + return; + } + + grub_memcpy (&tpm2_protector_ctx.token, t, sizeof(grub_luks2_token_t)); + if (tpm2_protector_ctx.token.type == LUKS2_TOKEN_TYPE_SYSTEMD_TPM2) + { + tpm2_protector_ctx.token.u.systemd_tpm2.base64_blob = + grub_strdup (tpm2_protector_ctx.token.u.systemd_tpm2.base64_blob); + tpm2_protector_ctx.token.u.systemd_tpm2.hex_policy_hash = + grub_strdup (tpm2_protector_ctx.token.u.systemd_tpm2.hex_policy_hash); + if (tpm2_protector_ctx.token.u.systemd_tpm2.base64_srk != NULL) + tpm2_protector_ctx.token.u.systemd_tpm2.base64_srk = + grub_strdup (tpm2_protector_ctx.token.u.systemd_tpm2.base64_srk); + } +} + static grub_err_t tpm2_protector_init_cmd_handler (grub_extcmd_context_t ctxt, int argc, char **args __attribute__ ((unused))) { struct grub_arg_list *state = ctxt->state; + const char *device = NULL; grub_err_t err; if (argc) return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("the TPM2 key protector does not accept any non-option arguments (i.e., like -o and/or --option only)")); grub_free ((void *) tpm2_protector_ctx.keyfile); + if (tpm2_protector_ctx.token.type == LUKS2_TOKEN_TYPE_SYSTEMD_TPM2) + { + grub_free ((void *) tpm2_protector_ctx.token.u.systemd_tpm2.base64_blob); + grub_free ((void *) tpm2_protector_ctx.token.u.systemd_tpm2.hex_policy_hash); + grub_free ((void *) tpm2_protector_ctx.token.u.systemd_tpm2.base64_srk); + } grub_memset (&tpm2_protector_ctx, 0, sizeof (tpm2_protector_ctx)); + tpm2_protector_ctx.keyslot_idx = -1; + tpm2_protector_ctx.token_idx = -1; if (state[OPTION_MODE].set) /* mode */ { @@ -1237,9 +1490,44 @@ tpm2_protector_init_cmd_handler (grub_extcmd_context_t ctxt, int argc, return err; } + if (state[OPTION_DEVICE].set) /* device */ + { + err = tpm2_protector_parse_device (state[OPTION_DEVICE].arg, &device); + if (err != GRUB_ERR_NONE) + return err; + } + + if (state[OPTION_KEYSLOT].set) + { + tpm2_protector_ctx.keyslot_idx = grub_strtol (state[OPTION_KEYSLOT].arg, 0, 10); + } + + if (state[OPTION_TOKEN].set) + { + tpm2_protector_ctx.token_idx = grub_strtol (state[OPTION_TOKEN].arg, 0, 10); + } + err = tpm2_protector_check_args (&tpm2_protector_ctx); - /* This command only initializes the protector, so nothing else to do. */ + if (device != NULL) + { + /* 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); + return err; + } + + luks2_iterate_keyslot(disk, LUKS2_ITERATE_FLAGS_WITH_TOKEN, luks2_iterate_fct); + + if (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 + tpm2_protector_ctx.mode = TPM2_PROTECTOR_MODE_LUKS2_TOKEN; + + grub_disk_close(disk); + } return err; } @@ -1252,7 +1540,15 @@ tpm2_protector_clear_cmd_handler (grub_extcmd_context_t ctxt __attribute__ ((unu return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("tpm2_key_protector_clear accepts no arguments")); grub_free ((void *) tpm2_protector_ctx.keyfile); + if (tpm2_protector_ctx.token.type == LUKS2_TOKEN_TYPE_SYSTEMD_TPM2) + { + grub_free ((void *) tpm2_protector_ctx.token.u.systemd_tpm2.base64_blob); + grub_free ((void *) tpm2_protector_ctx.token.u.systemd_tpm2.hex_policy_hash); + grub_free ((void *) tpm2_protector_ctx.token.u.systemd_tpm2.base64_srk); + } grub_memset (&tpm2_protector_ctx, 0, sizeof (tpm2_protector_ctx)); + tpm2_protector_ctx.keyslot_idx = -1; + tpm2_protector_ctx.token_idx = -1; return GRUB_ERR_NONE; } @@ -1320,6 +1616,12 @@ GRUB_MOD_INIT (tpm2_key_protector) GRUB_MOD_FINI (tpm2_key_protector) { grub_free ((void *) tpm2_protector_ctx.keyfile); + if (tpm2_protector_ctx.token.type == LUKS2_TOKEN_TYPE_SYSTEMD_TPM2) + { + grub_free ((void *) tpm2_protector_ctx.token.u.systemd_tpm2.base64_blob); + grub_free ((void *) tpm2_protector_ctx.token.u.systemd_tpm2.hex_policy_hash); + grub_free ((void *) tpm2_protector_ctx.token.u.systemd_tpm2.base64_srk); + } grub_key_protector_unregister (&tpm2_key_protector); grub_unregister_extcmd (tpm2_protector_clear_cmd); diff --git a/grub-core/commands/tpm2_key_protector/tpm2_luks2.c b/grub-core/commands/tpm2_key_protector/tpm2_luks2.c new file mode 100644 index 000000000..de0a7f01f --- /dev/null +++ b/grub-core/commands/tpm2_key_protector/tpm2_luks2.c @@ -0,0 +1,280 @@ +/* + * 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 <tss2_buffer.h> +#include <tss2_mu.h> +#include <tss2_iesys.h> + +#include "tpm2.h" +#include "tpm2srk.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_unmarshal_srk (const void *srk, + grub_size_t srk_size, + TPM_IESYS_RESOURCE_t *rsrc) +{ + struct grub_tpm2_buffer buf; + + grub_tpm2_buffer_init (&buf); + if (srk_size > buf.cap) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("srk larger than %llu bytes"), (unsigned long long)buf.cap); + + grub_memcpy (buf.data, srk, srk_size); + buf.size = srk_size; + + grub_Tss2_IESYS_RESOURCE_Unmarshal(&buf, rsrc); + + 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, + const void *srk_data, + grub_size_t srk_data_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; + TPM_IESYS_RESOURCE_t rsrc = {0}; + + 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"); + } + + parent_handle = TPM_RH_OWNER; + + if (srk_data != NULL) + { + err = tpm2_luks2_unmarshal_srk(srk_data, srk_data_size, &rsrc); + if (err != GRUB_ERR_NONE) + { + grub_print_error (); + return grub_error (GRUB_ERR_BAD_ARGUMENT, "Can't load srk from header"); + } + srk_handle = rsrc.handle; + } + else if (TPM_HT_IS_PERSISTENT (parent_handle)) + { + srk_handle = parent_handle; + } + else + { + /* 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; + } + } + + /* 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/tpm2_key_protector/tpm2_luks2.h b/grub-core/commands/tpm2_key_protector/tpm2_luks2.h new file mode 100644 index 000000000..face1a594 --- /dev/null +++ b/grub-core/commands/tpm2_key_protector/tpm2_luks2.h @@ -0,0 +1,39 @@ +/* + * 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, + const void *srk_data, + grub_size_t srk_data_size, + void **ret_decrypted_key, + grub_size_t *ret_decrypted_key_size); + +#endif /* GRUB_SYSTEMD_TPM2_LUKS2_TPM2_HEADER */ -- 2.39.5 _______________________________________________ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel