@node tpm2_key_protector_init
@subsection tpm2_key_protector_init
-@deffn Command tpm2_key_protector_init [@option{--mode} | @option{-m} mode] | [@option{--pcrs} | @option{-p} pcrlist] | [@option{--bank} | @option{-b} pcrbank] | [ [@option{--tpm2key} | @option{-T} tpm2key_file] | [@option{--keyfile} | @option{-k} keyfile] ] | [@option{--srk} | @option{-s} handle] | [@option{--asymmetric} | @option{-a} srk_type] | [@option{--nvindex} | @option{-n} nv_index]
+@deffn Command tpm2_key_protector_init [@option{--mode} | @option{-m} mode] | [@option{--pcrs} | @option{-p} pcrlist] | [@option{--bank} | @option{-b} pcrbank] | [@option{--cap-pcrs} | @option{-c} pcrlist] | [ [@option{--tpm2key} | @option{-T} tpm2key_file] | [@option{--keyfile} | @option{-k} keyfile] ] | [@option{--srk} | @option{-s} handle] | [@option{--asymmetric} | @option{-a} srk_type] | [@option{--nvindex} | @option{-n} nv_index]
Initialize the TPM2 key protector to unseal the key for the @command{cryptomount}
(@pxref{cryptomount}) command. There are two supported modes,
SRK(@kbd{srk}) and NV index(@kbd{nv}), to be specified by the option
bank is chosen by selecting a hash algorithm. The current supported PCR banks
are SHA1, SHA256, SHA384, and SHA512, and the default is SHA256.
+The @option{-c} option is introduced to enable the "capping" of a specified list of
+PCRs. This feature addresses scenarios where a user wants to ensure a sealed key
+cannot be unsealed again after its initial use. When the @option{-c} option is
+employed, and the key is successfully unsealed, the TPM2 key protector automatically
+extends the selected PCRs with an EV_SEPARATOR event. This action cryptographically
+alters the PCR values, thereby preventing the associated key from being unsealed in
+any subsequent attempts until those specific PCRs are reset to their original state,
+which typically occurs during a system reboot. In general, it is sufficient to
+extend one associated PCR to cap the key.
+
+It's noteworthy that a key sealed against PCR 8 naturally incorporates a "capping"
+behavior, even without explicitly using a @option{-c} option. This is because GRUB
+measures all commands into PCR 8, including those from configuration files. As a
+result, the value of PCR 8 changes with virtually every command execution during
+the boot process. Consequently, a key sealed against PCR 8 can only be unsealed
+once in a given boot session, as any subsequent GRUB command will alter PCR 8,
+invalidating the unsealing policy and effectively "capping" the key.
+
Some options are only available for the specific mode. The SRK-specific
options are @option{-T}, @option{-k}, @option{-a}, and @option{-s}. On the
other hand, the NV index-specific option is @option{-n}.
#include <tss2_buffer.h>
#include <tss2_types.h>
#include <tss2_mu.h>
+#include <tcg2.h>
#include "tpm2_args.h"
#include "tpm2.h"
OPTION_MODE,
OPTION_PCRS,
OPTION_BANK,
+ OPTION_CAPPCRS,
OPTION_TPM2KEY,
OPTION_KEYFILE,
OPTION_SRK,
grub_uint8_t pcr_count;
grub_srk_type_t srk_type;
TPM_ALG_ID_t bank;
+ grub_uint8_t cap_pcrs[TPM_MAX_PCRS];
+ grub_uint8_t cap_pcr_count;
const char *tpm2key;
const char *keyfile;
TPM_HANDLE_t srk;
N_("Bank of PCRs used to authorize key release: "
"SHA1, SHA256, SHA384 or SHA512. (default: SHA256)"),
},
+ {
+ .longarg = "cap-pcrs",
+ .shortarg = 'c',
+ .flags = 0,
+ .arg = NULL,
+ .type = ARG_TYPE_STRING,
+ .doc =
+ N_("Comma-separated list of PCRs to be capped after key release "
+ "e.g., '7,11'."),
+ },
/* SRK-mode options */
{
.longarg = "tpm2key",
return err;
}
+static grub_err_t
+tpm2_protector_cap_pcrs (const tpm2_protector_context_t *ctx)
+{
+ grub_uint8_t i;
+ grub_err_t err;
+
+ for (i = 0; i < ctx->cap_pcr_count; i++)
+ {
+ err = grub_tcg2_cap_pcr (ctx->cap_pcrs[i]);
+ if (err != GRUB_ERR_NONE)
+ return err;
+ }
+
+ return GRUB_ERR_NONE;
+}
+
static grub_err_t
tpm2_protector_recover (const tpm2_protector_context_t *ctx,
grub_uint8_t **key, grub_size_t *key_size)
{
+ grub_err_t err;
+
switch (ctx->mode)
{
case TPM2_PROTECTOR_MODE_SRK:
- return tpm2_protector_srk_recover (ctx, key, key_size);
+ err = tpm2_protector_srk_recover (ctx, key, key_size);
+ break;
case TPM2_PROTECTOR_MODE_NV:
- return tpm2_protector_nv_recover (ctx, key, key_size);
+ err = tpm2_protector_nv_recover (ctx, key, key_size);
+ break;
default:
- return GRUB_ERR_BAD_ARGUMENT;
+ err = grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Unknown Mode"));
}
+
+ /* Cap the selected PCRs when the key is unsealed successfully */
+ if (ctx->cap_pcr_count > 0 && err == GRUB_ERR_NONE)
+ err = tpm2_protector_cap_pcrs (ctx);
+
+ return err;
}
static grub_err_t
return err;
}
+ if (state[OPTION_CAPPCRS].set) /* cap-pcrs */
+ {
+ err = grub_tpm2_protector_parse_pcrs (state[OPTION_CAPPCRS].arg,
+ tpm2_protector_ctx.cap_pcrs,
+ &tpm2_protector_ctx.cap_pcr_count);
+ if (err != GRUB_ERR_NONE)
+ return err;
+ }
+
if (state[OPTION_TPM2KEY].set) /* tpm2key */
{
err = tpm2_protector_parse_file (state[OPTION_TPM2KEY].arg,
N_("[-m mode] "
"[-p pcr_list] "
"[-b pcr_bank] "
+ "[-c pcr_list] "
"[-T tpm2_key_file_path] "
"[-k sealed_key_file_path] "
"[-s srk_handle] "
"feature_default_font_path", "feature_all_video_module",
"feature_menuentry_id", "feature_menuentry_options", "feature_200_final",
"feature_nativedisk_cmd", "feature_timeout_style",
- "feature_search_cryptodisk_only"
+ "feature_search_cryptodisk_only", "feature_tpm2_cap_pcrs"
};
GRUB_MOD_INIT(normal)