From 43a59b8b86b0c5106d0ec90568b1b55dc6bc19a3 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 17 Apr 2024 19:04:29 +0200 Subject: [PATCH] pcrlock: rework --recovery-pin= to take three different arguments This reworkds --recovery-pin= from a parameter that takes a boolean to an enum supporting one of "hide", "show", "query". If "hide" (default behaviour) we'll generate a recovery pin automatically, but never show it, and thus just seal it and good. If "show" we'll generate a recovery pin automatically, but display it in the output, so the user can write it down. If "query" we'll ask the user for a recovery pin, and not automatically generate any. For compatibility the old boolean behaviour is kept. With this you can now do "systemd-pcrlock make-policy --recovery-pin=show" to set up the first policy, write down the recovery PIN. Later, if the PCR prediction didn't work out one day you can then do "systemd-pcrlock make-policy --recovery-pin=query" and enter the recovery key and write a new policy. --- man/systemd-pcrlock.xml | 17 ++++++++++------- src/pcrlock/pcrlock.c | 38 +++++++++++++++++++++++++++++++------- 2 files changed, 41 insertions(+), 14 deletions(-) diff --git a/man/systemd-pcrlock.xml b/man/systemd-pcrlock.xml index 2c674a34b4c..e2e861b2467 100644 --- a/man/systemd-pcrlock.xml +++ b/man/systemd-pcrlock.xml @@ -504,13 +504,16 @@ - Takes a boolean. Defaults to false. Honoured by make-policy. If - true, will query the user for a PIN to unlock the TPM2 NV index with. If no policy was created before - this PIN is used to protect the newly allocated NV index. If a policy has been created before the PIN - is used to unlock write access to the NV index. If this option is not used a PIN is automatically - generated. Regardless if user supplied or automatically generated, it is stored in encrypted form in - the policy metadata file. The recovery PIN may be used to regain write access to an NV index in case - the access policy became out of date. + Takes one of hide, show or + query. Defaults to hide. Honoured by + make-policy. If query, will query the user for a PIN to unlock + the TPM2 NV index with. If no policy was created before, this PIN is used to protect the newly + allocated NV index. If a policy has been created before, the PIN is used to unlock write access to + the NV index. If either hide or show is used, a PIN is + automatically generated, and — only in case of show — displayed on + screen. Regardless if user supplied or automatically generated, it is stored in encrypted form in the + policy metadata file. The recovery PIN may be used to regain write access to an NV index in case the + access policy became out of date. diff --git a/src/pcrlock/pcrlock.c b/src/pcrlock/pcrlock.c index 6651b1e3e1e..33cdafc06ef 100644 --- a/src/pcrlock/pcrlock.c +++ b/src/pcrlock/pcrlock.c @@ -43,6 +43,7 @@ #include "random-util.h" #include "recovery-key.h" #include "sort-util.h" +#include "string-table.h" #include "terminal-util.h" #include "tpm2-util.h" #include "unaligned.h" @@ -52,6 +53,14 @@ #include "varlink-io.systemd.PCRLock.h" #include "verbs.h" +typedef enum RecoveryPinMode { + RECOVERY_PIN_HIDE, /* generate a recovery PIN automatically, but don't show it (alias: "no") */ + RECOVERY_PIN_SHOW, /* generate a recovery PIN automatically, and display it to the user */ + RECOVERY_PIN_QUERY, /* asks the user for a PIN to use interactively (alias: "yes") */ + _RECOVERY_PIN_MODE_MAX, + _RECOVERY_PIN_MODE_INVALID = -EINVAL, +} RecoveryPinMode; + static PagerFlags arg_pager_flags = 0; static JsonFormatFlags arg_json_format_flags = JSON_FORMAT_OFF|JSON_FORMAT_NEWLINE; static char **arg_components = NULL; @@ -62,7 +71,7 @@ static bool arg_raw_description = false; static char *arg_location_start = NULL; static char *arg_location_end = NULL; static TPM2_HANDLE arg_nv_index = 0; -static bool arg_recovery_pin = false; +static RecoveryPinMode arg_recovery_pin = RECOVERY_PIN_HIDE; static char *arg_policy_path = NULL; static bool arg_force = false; static BootEntryTokenType arg_entry_token_type = BOOT_ENTRY_TOKEN_AUTO; @@ -104,6 +113,14 @@ STATIC_DESTRUCTOR_REGISTER(arg_entry_token, freep); (UINT32_C(1) << TPM2_PCR_SHIM_POLICY) | \ (UINT32_C(1) << TPM2_PCR_SYSTEM_IDENTITY)) +static const char* recovery_pin_mode_table[_RECOVERY_PIN_MODE_MAX] = { + [RECOVERY_PIN_HIDE] = "hide", + [RECOVERY_PIN_SHOW] = "show", + [RECOVERY_PIN_QUERY] = "query", +}; + +DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(recovery_pin_mode, RecoveryPinMode, RECOVERY_PIN_QUERY); + typedef struct EventLogRecordBank EventLogRecordBank; typedef struct EventLogRecord EventLogRecord; typedef struct EventLogRegisterBank EventLogRegisterBank; @@ -4320,7 +4337,7 @@ static int write_boot_policy_file(const char *json_text) { return 1; } -static int make_policy(bool force, bool recovery_pin) { +static int make_policy(bool force, RecoveryPinMode recovery_pin_mode) { int r; /* Here's how this all works: after predicting all possible PCR values for next boot (with @@ -4444,7 +4461,7 @@ static int make_policy(bool force, bool recovery_pin) { /* Acquire a recovery PIN, either from the user, or create a randomized one */ _cleanup_(erase_and_freep) char *pin = NULL; - if (recovery_pin) { + if (recovery_pin_mode == RECOVERY_PIN_QUERY) { r = getenv_steal_erase("PIN", &pin); if (r < 0) return log_error_errno(r, "Failed to acquire PIN from environment: %m"); @@ -4476,6 +4493,13 @@ static int make_policy(bool force, bool recovery_pin) { r = make_recovery_key(&pin); if (r < 0) return log_error_errno(r, "Failed to generate a randomized recovery PIN: %m"); + + if (recovery_pin_mode == RECOVERY_PIN_SHOW) + printf("%s Selected recovery PIN is: %s%s%s\n", + special_glyph(SPECIAL_GLYPH_LOCK_AND_KEY), + ansi_highlight_cyan(), + pin, + ansi_normal()); } _cleanup_(tpm2_handle_freep) Tpm2Handle *nv_handle = NULL; @@ -5046,9 +5070,9 @@ static int parse_argv(int argc, char *argv[]) { } case ARG_RECOVERY_PIN: - r = parse_boolean_argument("--recovery-pin", optarg, &arg_recovery_pin); - if (r < 0) - return r; + arg_recovery_pin = recovery_pin_mode_from_string(optarg); + if (arg_recovery_pin < 0) + return log_error_errno(arg_recovery_pin, "Failed to parse --recovery-pin= mode: %s", optarg); break; case ARG_PCRLOCK: @@ -5212,7 +5236,7 @@ static int vl_method_make_policy(Varlink *link, JsonVariant *parameters, Varlink if (r != 0) return r; - r = make_policy(p.force, /* recovery_key= */ false); + r = make_policy(p.force, /* recovery_key= */ RECOVERY_PIN_HIDE); if (r < 0) return r; if (r == 0)