diff --git a/docs/grub.texi b/docs/grub.texi index d697010ce..25e602a56 100644 --- a/docs/grub.texi +++ b/docs/grub.texi @@ -8458,7 +8458,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 @@ -8473,6 +8473,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 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}. 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 #include #include +#include #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 a9e7a09d1..01b79ac32 100644 --- a/grub-core/normal/main.c +++ b/grub-core/normal/main.c @@ -518,7 +518,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)