> On 8 Jul 2025, at 2:01 PM, Gary Lin via Grub-devel <grub-devel@gnu.org> wrote: > > To prevent a sealed key from being unsealed again, a common and > straightforward method is to "cap" the key by extending the associated > PCRs. When the PCRs associated with the sealed key are extended, TPM will > be unable to unseal the key, as the PCR values required for unsealing no > longer match, effectively rendering the key unusable until the next > system boot or a state where the PCRs are reset to their expected values. > > To cap a specific set of PCRs, simply append the argument '-c pcr_list' > to the tpm2_key_protector command. Upon successfully unsealing the key, > the TPM2 key protector will then invoke tpm2_protector_cap_pcrs(). This > function extends the selected PCRs with a SEPARATOR event, effectively > "capping" them. Consequently, the associated key cannot be unsealed in > any subsequent attempts until these PCRs are reset to their original, > pre-capped state, typically occurring upon the next system boot. > > Signed-off-by: Gary Lin <g...@suse.com> > ---
Reviewed-by: Sudhakar Kuppusamy <sudha...@linux.ibm.com> > docs/grub.texi | 20 ++++++- > .../commands/tpm2_key_protector/module.c | 56 ++++++++++++++++++- > grub-core/normal/main.c | 2 +- > 3 files changed, 73 insertions(+), 5 deletions(-) > > diff --git a/docs/grub.texi b/docs/grub.texi > index 34b3484dc..bd35e9d46 100644 > --- a/docs/grub.texi > +++ b/docs/grub.texi > @@ -8084,7 +8084,7 @@ either @var{expression1} or @var{expression2} is true > @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 > @@ -8099,6 +8099,24 @@ bank that the key is sealed with. The PCR list is a > comma-separated list, e.g., > 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 a 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}. > diff --git a/grub-core/commands/tpm2_key_protector/module.c > b/grub-core/commands/tpm2_key_protector/module.c > index b84c2234f..1226b65e0 100644 > --- a/grub-core/commands/tpm2_key_protector/module.c > +++ b/grub-core/commands/tpm2_key_protector/module.c > @@ -28,6 +28,7 @@ > #include <tss2_buffer.h> > #include <tss2_types.h> > #include <tss2_mu.h> > +#include <tcg2.h> > > #include "tpm2_args.h" > #include "tpm2.h" > @@ -47,6 +48,7 @@ typedef enum tpm2_protector_options > OPTION_MODE, > OPTION_PCRS, > OPTION_BANK, > + OPTION_CAPPCRS, > OPTION_TPM2KEY, > OPTION_KEYFILE, > OPTION_SRK, > @@ -61,6 +63,8 @@ typedef struct tpm2_protector_context > 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; > @@ -100,6 +104,16 @@ static const struct grub_arg_option > tpm2_protector_init_cmd_options[] = > 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", > @@ -1212,19 +1226,45 @@ tpm2_protector_nv_recover (const > tpm2_protector_context_t *ctx, > 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 > @@ -1364,6 +1404,15 @@ tpm2_protector_init_cmd_handler (grub_extcmd_context_t > ctxt, int argc, > 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, > @@ -1465,6 +1514,7 @@ GRUB_MOD_INIT (tpm2_key_protector) > 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] " > diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c > index 96abfda2f..f823851c4 100644 > --- a/grub-core/normal/main.c > +++ b/grub-core/normal/main.c > @@ -512,7 +512,7 @@ static const char *features[] = { > "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) > -- > 2.43.0 > > > _______________________________________________ > Grub-devel mailing list > Grub-devel@gnu.org > https://lists.gnu.org/mailman/listinfo/grub-devel
_______________________________________________ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel