]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
pcrlock: rework --recovery-pin= to take three different arguments
authorLennart Poettering <lennart@poettering.net>
Wed, 17 Apr 2024 17:04:29 +0000 (19:04 +0200)
committerLennart Poettering <lennart@poettering.net>
Thu, 18 Apr 2024 16:12:24 +0000 (18:12 +0200)
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
src/pcrlock/pcrlock.c

index 2c674a34b4c0a94c4d8fe54853e33c5d794a510c..e2e861b246796e58c6a5d92a68bad3a9726531c2 100644 (file)
       <varlistentry>
         <term><option>--recovery-pin=</option></term>
 
-        <listitem><para>Takes a boolean. Defaults to false. Honoured by <command>make-policy</command>. 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.</para>
+        <listitem><para>Takes one of <literal>hide</literal>, <literal>show</literal> or
+        <literal>query</literal>. Defaults to <literal>hide</literal>. Honoured by
+        <command>make-policy</command>. If <literal>query</literal>, 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 <literal>hide</literal> or <literal>show</literal> is used, a PIN is
+        automatically generated, and — only in case of <literal>show</literal> — 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.</para>
 
         <xi:include href="version-info.xml" xpointer="v255"/></listitem>
       </varlistentry>
index 6651b1e3e1ee209d08c08cd3ec17170ea1523632..33cdafc06ef62dd771cd0cf956479fef25dda029 100644 (file)
@@ -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"
 #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)