mirror of
https://github.com/systemd/systemd
synced 2024-07-21 18:24:38 +00:00
Merge pull request #30130 from poettering/pcrlock-root
pcrlock: add support for unlocking a root fs with a pcrlock file
This commit is contained in:
commit
f70daee8f2
|
@ -155,6 +155,19 @@
|
|||
<para>If the new prediction matches the old this command terminates quickly and executes no further
|
||||
operation. (Unless <option>--force</option> is specified, see below.)</para>
|
||||
|
||||
<para>Starting with v256, a copy of the <filename>/var/lib/systemd/pcrlock.json</filename> policy
|
||||
file is encoded in a credential (see
|
||||
<citerefentry><refentrytitle>systemd-creds</refentrytitle><manvolnum>1</manvolnum></citerefentry> for
|
||||
details) and written to the EFI System Partition or XBOOTLDR partition, in the
|
||||
<filename>/loader/credentials/</filename> subdirectory. There it is picked up at boot by
|
||||
<citerefentry><refentrytitle>systemd-stub</refentrytitle><manvolnum>7</manvolnum></citerefentry> and
|
||||
passed to the invoked initrd, where it can be used to unlock the root file system (which typically
|
||||
contains <filename>/var/</filename>, which is where the primary copy of the policy is located, which
|
||||
hence cannot be used to unlock the root file system). The credential file is named after the boot
|
||||
entry token of the installation (see
|
||||
<citerefentry><refentrytitle>bootctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>), which
|
||||
is configurable via the <option>--entry-token=</option> switch, see below.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v255"/>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
@ -531,6 +544,18 @@
|
|||
<xi:include href="version-info.xml" xpointer="v255"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--entry-token=</option></term>
|
||||
|
||||
<listitem><para>Sets the boot entry token to use for the file name for the pcrlock policy credential
|
||||
in the EFI System Partition or XBOOTLDR partition. See the
|
||||
<citerefentry><refentrytitle>bootctl</refentrytitle><manvolnum>1</manvolnum></citerefentry> option of
|
||||
the same regarding expected values. This switch has an effect on the
|
||||
<command>make-policy</command> command only.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v256"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<xi:include href="standard-options.xml" xpointer="json" />
|
||||
<xi:include href="standard-options.xml" xpointer="no-pager" />
|
||||
<xi:include href="standard-options.xml" xpointer="help" />
|
||||
|
@ -553,6 +578,9 @@
|
|||
<member><citerefentry><refentrytitle>systemd-cryptsetup@.service</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
|
||||
<member><citerefentry><refentrytitle>systemd-repart</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
|
||||
<member><citerefentry><refentrytitle>systemd-pcrmachine.service</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
|
||||
<member><citerefentry><refentrytitle>systemd-creds</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
|
||||
<member><citerefentry><refentrytitle>systemd-stub</refentrytitle><manvolnum>7</manvolnum></citerefentry></member>
|
||||
<member><citerefentry><refentrytitle>bootctl</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
|
||||
</simplelist></para>
|
||||
</refsect1>
|
||||
|
||||
|
|
|
@ -365,6 +365,7 @@ int enroll_tpm2(struct crypt_device *cd,
|
|||
&IOVEC_MAKE(policy.buffer, policy.size),
|
||||
use_pin ? &IOVEC_MAKE(binary_salt, sizeof(binary_salt)) : NULL,
|
||||
&srk,
|
||||
pcrlock_path ? &pcrlock_policy.nv_handle : NULL,
|
||||
flags,
|
||||
&v);
|
||||
if (r < 0)
|
||||
|
|
|
@ -42,7 +42,7 @@ _public_ int cryptsetup_token_open_pin(
|
|||
void *usrptr /* plugin defined parameter passed to crypt_activate_by_token*() API */) {
|
||||
|
||||
_cleanup_(erase_and_freep) char *base64_encoded = NULL, *pin_string = NULL;
|
||||
_cleanup_(iovec_done) struct iovec blob = {}, pubkey = {}, policy_hash = {}, salt = {}, srk = {};
|
||||
_cleanup_(iovec_done) struct iovec blob = {}, pubkey = {}, policy_hash = {}, salt = {}, srk = {}, pcrlock_nv = {};
|
||||
_cleanup_(iovec_done_erase) struct iovec decrypted_key = {};
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
|
||||
uint32_t hash_pcr_mask, pubkey_pcr_mask;
|
||||
|
@ -88,6 +88,7 @@ _public_ int cryptsetup_token_open_pin(
|
|||
&policy_hash,
|
||||
&salt,
|
||||
&srk,
|
||||
&pcrlock_nv,
|
||||
&flags);
|
||||
if (r < 0)
|
||||
return log_debug_open_error(cd, r);
|
||||
|
@ -109,6 +110,7 @@ _public_ int cryptsetup_token_open_pin(
|
|||
&policy_hash,
|
||||
&salt,
|
||||
&srk,
|
||||
&pcrlock_nv,
|
||||
flags,
|
||||
&decrypted_key);
|
||||
if (r < 0)
|
||||
|
@ -166,7 +168,7 @@ _public_ void cryptsetup_token_dump(
|
|||
const char *json /* validated 'systemd-tpm2' token if cryptsetup_token_validate is defined */) {
|
||||
|
||||
_cleanup_free_ char *hash_pcrs_str = NULL, *pubkey_pcrs_str = NULL, *blob_str = NULL, *policy_hash_str = NULL, *pubkey_str = NULL;
|
||||
_cleanup_(iovec_done) struct iovec blob = {}, pubkey = {}, policy_hash = {}, salt = {}, srk = {};
|
||||
_cleanup_(iovec_done) struct iovec blob = {}, pubkey = {}, policy_hash = {}, salt = {}, srk = {}, pcrlock_nv = {};
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
|
||||
uint32_t hash_pcr_mask, pubkey_pcr_mask;
|
||||
uint16_t pcr_bank, primary_alg;
|
||||
|
@ -191,6 +193,7 @@ _public_ void cryptsetup_token_dump(
|
|||
&policy_hash,
|
||||
&salt,
|
||||
&srk,
|
||||
&pcrlock_nv,
|
||||
&flags);
|
||||
if (r < 0)
|
||||
return (void) crypt_log_debug_errno(cd, r, "Failed to parse " TOKEN_NAME " JSON fields: %m");
|
||||
|
@ -226,6 +229,7 @@ _public_ void cryptsetup_token_dump(
|
|||
crypt_log(cd, "\ttpm2-pcrlock: %s\n", true_false(flags & TPM2_FLAGS_USE_PCRLOCK));
|
||||
crypt_log(cd, "\ttpm2-salt: %s\n", true_false(iovec_is_set(&salt)));
|
||||
crypt_log(cd, "\ttpm2-srk: %s\n", true_false(iovec_is_set(&srk)));
|
||||
crypt_log(cd, "\ttpm2-pcrlock-nv: %s\n", true_false(iovec_is_set(&pcrlock_nv)));
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -27,6 +27,7 @@ int acquire_luks2_key(
|
|||
const struct iovec *policy_hash,
|
||||
const struct iovec *salt,
|
||||
const struct iovec *srk,
|
||||
const struct iovec *pcrlock_nv,
|
||||
TPM2Flags flags,
|
||||
struct iovec *ret_decrypted_key) {
|
||||
|
||||
|
@ -75,6 +76,14 @@ int acquire_luks2_key(
|
|||
r = tpm2_pcrlock_policy_load(pcrlock_path, &pcrlock_policy);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0) {
|
||||
/* Not found? Then search among passed credentials */
|
||||
r = tpm2_pcrlock_policy_from_credentials(srk, pcrlock_nv, &pcrlock_policy);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EREMOTE), "Couldn't find pcrlock policy for volume.");
|
||||
}
|
||||
}
|
||||
|
||||
_cleanup_(tpm2_context_unrefp) Tpm2Context *tpm2_context = NULL;
|
||||
|
|
|
@ -20,5 +20,6 @@ int acquire_luks2_key(
|
|||
const struct iovec *policy_hash,
|
||||
const struct iovec *salt,
|
||||
const struct iovec *srk,
|
||||
const struct iovec *pcrlock_nv,
|
||||
TPM2Flags flags,
|
||||
struct iovec *decrypted_key);
|
||||
|
|
|
@ -70,6 +70,7 @@ int acquire_tpm2_key(
|
|||
const struct iovec *policy_hash,
|
||||
const struct iovec *salt,
|
||||
const struct iovec *srk,
|
||||
const struct iovec *pcrlock_nv,
|
||||
TPM2Flags flags,
|
||||
usec_t until,
|
||||
bool headless,
|
||||
|
@ -128,6 +129,14 @@ int acquire_tpm2_key(
|
|||
r = tpm2_pcrlock_policy_load(pcrlock_path, &pcrlock_policy);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0) {
|
||||
/* Not found? Then search among passed credentials */
|
||||
r = tpm2_pcrlock_policy_from_credentials(srk, pcrlock_nv, &pcrlock_policy);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EREMOTE), "Couldn't find pcrlock policy for volume.");
|
||||
}
|
||||
}
|
||||
|
||||
_cleanup_(tpm2_context_unrefp) Tpm2Context *tpm2_context = NULL;
|
||||
|
@ -219,6 +228,7 @@ int find_tpm2_auto_data(
|
|||
struct iovec *ret_policy_hash,
|
||||
struct iovec *ret_salt,
|
||||
struct iovec *ret_srk,
|
||||
struct iovec *ret_pcrlock_nv,
|
||||
TPM2Flags *ret_flags,
|
||||
int *ret_keyslot,
|
||||
int *ret_token) {
|
||||
|
@ -228,7 +238,7 @@ int find_tpm2_auto_data(
|
|||
assert(cd);
|
||||
|
||||
for (token = start_token; token < sym_crypt_token_max(CRYPT_LUKS2); token++) {
|
||||
_cleanup_(iovec_done) struct iovec blob = {}, policy_hash = {}, pubkey = {}, salt = {}, srk = {};
|
||||
_cleanup_(iovec_done) struct iovec blob = {}, policy_hash = {}, pubkey = {}, salt = {}, srk = {}, pcrlock_nv = {};
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
|
||||
uint32_t hash_pcr_mask, pubkey_pcr_mask;
|
||||
uint16_t pcr_bank, primary_alg;
|
||||
|
@ -253,6 +263,7 @@ int find_tpm2_auto_data(
|
|||
&policy_hash,
|
||||
&salt,
|
||||
&srk,
|
||||
&pcrlock_nv,
|
||||
&flags);
|
||||
if (r == -EUCLEAN) /* Gracefully handle issues in JSON fields not owned by us */
|
||||
continue;
|
||||
|
@ -276,6 +287,7 @@ int find_tpm2_auto_data(
|
|||
*ret_keyslot = keyslot;
|
||||
*ret_token = token;
|
||||
*ret_srk = TAKE_STRUCT(srk);
|
||||
*ret_pcrlock_nv = TAKE_STRUCT(pcrlock_nv);
|
||||
*ret_flags = flags;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ int acquire_tpm2_key(
|
|||
const struct iovec *policy_hash,
|
||||
const struct iovec *salt,
|
||||
const struct iovec *srk,
|
||||
const struct iovec *pcrlock_nv,
|
||||
TPM2Flags flags,
|
||||
usec_t until,
|
||||
bool headless,
|
||||
|
@ -47,6 +48,7 @@ int find_tpm2_auto_data(
|
|||
struct iovec *ret_policy_hash,
|
||||
struct iovec *ret_salt,
|
||||
struct iovec *ret_srk,
|
||||
struct iovec *ret_pcrlock_nv,
|
||||
TPM2Flags *ret_flags,
|
||||
int *ret_keyslot,
|
||||
int *ret_token);
|
||||
|
@ -70,6 +72,7 @@ static inline int acquire_tpm2_key(
|
|||
const struct iovec *policy_hash,
|
||||
const struct iovec *salt,
|
||||
const struct iovec *srk,
|
||||
const struct iovec *pcrlock_nv,
|
||||
TPM2Flags flags,
|
||||
usec_t until,
|
||||
bool headless,
|
||||
|
@ -93,6 +96,7 @@ static inline int find_tpm2_auto_data(
|
|||
struct iovec *ret_policy_hash,
|
||||
struct iovec *ret_salt,
|
||||
struct iovec *ret_srk,
|
||||
struct iovec *ret_pcrlock_nv,
|
||||
TPM2Flags *ret_flags,
|
||||
int *ret_keyslot,
|
||||
int *ret_token) {
|
||||
|
|
|
@ -1688,6 +1688,7 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2(
|
|||
/* policy_hash= */ NULL, /* we don't know the policy hash */
|
||||
/* salt= */ NULL,
|
||||
/* srk= */ NULL,
|
||||
/* pcrlock_nv= */ NULL,
|
||||
arg_tpm2_pin ? TPM2_FLAGS_USE_PIN : 0,
|
||||
until,
|
||||
arg_headless,
|
||||
|
@ -1732,7 +1733,7 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2(
|
|||
* works. */
|
||||
|
||||
for (;;) {
|
||||
_cleanup_(iovec_done) struct iovec pubkey = {}, salt = {}, srk = {};
|
||||
_cleanup_(iovec_done) struct iovec pubkey = {}, salt = {}, srk = {}, pcrlock_nv = {};
|
||||
uint32_t hash_pcr_mask, pubkey_pcr_mask;
|
||||
uint16_t pcr_bank, primary_alg;
|
||||
TPM2Flags tpm2_flags;
|
||||
|
@ -1750,6 +1751,7 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2(
|
|||
&policy_hash,
|
||||
&salt,
|
||||
&srk,
|
||||
&pcrlock_nv,
|
||||
&tpm2_flags,
|
||||
&keyslot,
|
||||
&token);
|
||||
|
@ -1784,6 +1786,7 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2(
|
|||
&policy_hash,
|
||||
&salt,
|
||||
&srk,
|
||||
&pcrlock_nv,
|
||||
tpm2_flags,
|
||||
until,
|
||||
arg_headless,
|
||||
|
|
|
@ -3929,6 +3929,7 @@ static int partition_encrypt(Context *context, Partition *p, PartitionTarget *ta
|
|||
&IOVEC_MAKE(policy.buffer, policy.size),
|
||||
/* salt= */ NULL, /* no salt because tpm2_seal has no pin */
|
||||
&srk,
|
||||
&pcrlock_policy.nv_handle,
|
||||
flags,
|
||||
&v);
|
||||
if (r < 0)
|
||||
|
|
|
@ -9,15 +9,18 @@
|
|||
|
||||
#include "ask-password-api.h"
|
||||
#include "blockdev-util.h"
|
||||
#include "boot-entry.h"
|
||||
#include "build.h"
|
||||
#include "chase.h"
|
||||
#include "color-util.h"
|
||||
#include "conf-files.h"
|
||||
#include "creds-util.h"
|
||||
#include "efi-api.h"
|
||||
#include "env-util.h"
|
||||
#include "escape.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
#include "find-esp.h"
|
||||
#include "format-table.h"
|
||||
#include "format-util.h"
|
||||
#include "fs-util.h"
|
||||
|
@ -60,12 +63,15 @@ static TPM2_HANDLE arg_nv_index = 0;
|
|||
static bool arg_recovery_pin = false;
|
||||
static char *arg_policy_path = NULL;
|
||||
static bool arg_force = false;
|
||||
static BootEntryTokenType arg_entry_token_type = BOOT_ENTRY_TOKEN_AUTO;
|
||||
static char *arg_entry_token = NULL;
|
||||
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_components, strv_freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_pcrlock_path, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_location_start, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_location_end, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_policy_path, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_entry_token, freep);
|
||||
|
||||
#define PCRLOCK_SECUREBOOT_POLICY_PATH "/var/lib/pcrlock.d/240-secureboot-policy.pcrlock.d/generated.pcrlock"
|
||||
#define PCRLOCK_FIRMWARE_CODE_EARLY_PATH "/var/lib/pcrlock.d/250-firmware-code-early.pcrlock.d/generated.pcrlock"
|
||||
|
@ -4164,6 +4170,127 @@ static int remove_policy_file(const char *path) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int determine_boot_policy_file(char **ret) {
|
||||
_cleanup_free_ char *path = NULL, *fn = NULL, *joined = NULL;
|
||||
sd_id128_t machine_id;
|
||||
int r;
|
||||
|
||||
assert(ret);
|
||||
|
||||
r = find_xbootldr_and_warn(
|
||||
/* root= */ NULL,
|
||||
/* path= */ NULL,
|
||||
/* unprivileged_mode= */ false,
|
||||
&path,
|
||||
/* ret_uuid= */ NULL,
|
||||
/* ret_devid= */ NULL);
|
||||
if (r < 0) {
|
||||
if (r != -ENOKEY)
|
||||
return log_error_errno(r, "Failed to find XBOOTLDR partition: %m");
|
||||
|
||||
r = find_esp_and_warn(
|
||||
/* root= */ NULL,
|
||||
/* path= */ NULL,
|
||||
/* unprivileged_mode= */ false,
|
||||
&path,
|
||||
/* ret_part= */ NULL,
|
||||
/* ret_pstart= */ NULL,
|
||||
/* ret_psize= */ NULL,
|
||||
/* ret_uuid= */ NULL,
|
||||
/* ret_devid= */ NULL);
|
||||
if (r < 0) {
|
||||
if (r != -ENOKEY)
|
||||
return log_error_errno(r, "Failed to find ESP partition: %m");
|
||||
|
||||
*ret = NULL;
|
||||
return 0; /* not found! */
|
||||
}
|
||||
}
|
||||
|
||||
r = sd_id128_get_machine(&machine_id);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to read machine ID: %m");
|
||||
|
||||
r = boot_entry_token_ensure(
|
||||
/* root= */ NULL,
|
||||
"/etc/kernel",
|
||||
machine_id,
|
||||
/* machine_id_is_random = */ false,
|
||||
&arg_entry_token_type,
|
||||
&arg_entry_token);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
fn = strjoin("pcrlock.", arg_entry_token, ".cred");
|
||||
if (!fn)
|
||||
return log_oom();
|
||||
|
||||
if (!filename_is_valid(fn))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Credential name '%s' would not be a valid file name, refusing.", fn);
|
||||
|
||||
joined = path_join(path, "loader/credentials", fn);
|
||||
if (!joined)
|
||||
return log_oom();
|
||||
|
||||
*ret = TAKE_PTR(joined);
|
||||
return 1; /* found! */
|
||||
}
|
||||
|
||||
static int write_boot_policy_file(const char *json_text) {
|
||||
_cleanup_free_ char *boot_policy_file = NULL;
|
||||
int r;
|
||||
|
||||
assert(json_text);
|
||||
|
||||
r = determine_boot_policy_file(&boot_policy_file);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0) {
|
||||
log_info("Did not find XBOOTLDR/ESP partition, not writing boot policy file.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
_cleanup_free_ char *c = NULL;
|
||||
r = path_extract_filename(boot_policy_file, &c);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to extract file name from %s: %m", boot_policy_file);
|
||||
|
||||
ascii_strlower(c); /* lowercase this file, no matter what, since stored on VFAT, and we don't want to
|
||||
* run into case change incompatibilities */
|
||||
|
||||
_cleanup_(iovec_done) struct iovec encoded = {};
|
||||
r = encrypt_credential_and_warn(
|
||||
CRED_AES256_GCM_BY_NULL,
|
||||
c,
|
||||
now(CLOCK_REALTIME),
|
||||
/* not_after= */ USEC_INFINITY,
|
||||
/* tpm2_device= */ NULL,
|
||||
/* tpm2_hash_pcr_mask= */ 0,
|
||||
/* tpm2_pubkey_path= */ NULL,
|
||||
/* tpm2_pubkey_path_mask= */ 0,
|
||||
&IOVEC_MAKE_STRING(json_text),
|
||||
CREDENTIAL_ALLOW_NULL,
|
||||
&encoded);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to encode policy as credential: %m");
|
||||
|
||||
_cleanup_free_ char *base64_buf = NULL;
|
||||
ssize_t base64_size;
|
||||
base64_size = base64mem_full(encoded.iov_base, encoded.iov_len, 79, &base64_buf);
|
||||
if (base64_size < 0)
|
||||
return base64_size;
|
||||
|
||||
r = write_string_file(
|
||||
boot_policy_file,
|
||||
base64_buf,
|
||||
WRITE_STRING_FILE_ATOMIC|WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_SYNC|WRITE_STRING_FILE_MKDIR_0755);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to write boot policy file to '%s': %m", boot_policy_file);
|
||||
|
||||
log_info("Written new boot policy to '%s'.", boot_policy_file);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int verb_make_policy(int argc, char *argv[], void *userdata) {
|
||||
int r;
|
||||
|
||||
|
@ -4562,6 +4689,8 @@ static int verb_make_policy(int argc, char *argv[], void *userdata) {
|
|||
|
||||
log_info("Written new policy to '%s' and digest to TPM2 NV index 0x%x.", path, nv_index);
|
||||
|
||||
(void) write_boot_policy_file(text);
|
||||
|
||||
log_info("Overall time spent: %s", FORMAT_TIMESPAN(usec_sub_unsigned(now(CLOCK_MONOTONIC), start_usec), 1));
|
||||
|
||||
return 0;
|
||||
|
@ -4621,7 +4750,7 @@ static int undefine_policy_nv_index(
|
|||
}
|
||||
|
||||
static int verb_remove_policy(int argc, char *argv[], void *userdata) {
|
||||
int r;
|
||||
int ret = 0, r;
|
||||
|
||||
_cleanup_(tpm2_pcrlock_policy_done) Tpm2PCRLockPolicy policy = {};
|
||||
r = tpm2_pcrlock_policy_load(arg_policy_path, &policy);
|
||||
|
@ -4636,22 +4765,27 @@ static int verb_remove_policy(int argc, char *argv[], void *userdata) {
|
|||
r = undefine_policy_nv_index(policy.nv_index, &policy.nv_handle, &policy.srk_handle);
|
||||
if (r < 0)
|
||||
log_notice("Failed to remove NV index, assuming data out of date, removing policy file.");
|
||||
|
||||
RET_GATHER(ret, r);
|
||||
}
|
||||
|
||||
if (arg_policy_path) {
|
||||
r = remove_policy_file(arg_policy_path);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
} else {
|
||||
int ret = 0;
|
||||
|
||||
if (arg_policy_path)
|
||||
RET_GATHER(ret, remove_policy_file(arg_policy_path));
|
||||
else {
|
||||
RET_GATHER(ret, remove_policy_file("/var/lib/systemd/pcrlock.json"));
|
||||
RET_GATHER(ret, remove_policy_file("/run/systemd/pcrlock.json"));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
_cleanup_free_ char *boot_policy_file = NULL;
|
||||
r = determine_boot_policy_file(&boot_policy_file);
|
||||
if (r == 0)
|
||||
log_info("Did not find XBOOTLDR/ESP partition, not removing boot policy file.");
|
||||
else if (r > 0) {
|
||||
RET_GATHER(ret, remove_policy_file(boot_policy_file));
|
||||
} else
|
||||
RET_GATHER(ret, r);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int help(int argc, char *argv[], void *userdata) {
|
||||
|
@ -4711,6 +4845,8 @@ static int help(int argc, char *argv[], void *userdata) {
|
|||
" --pcrlock=PATH .pcrlock file to write expected PCR measurement to\n"
|
||||
" --policy=PATH JSON file to write policy output to\n"
|
||||
" --force Write policy even if it matches existing policy\n"
|
||||
" --entry-token=machine-id|os-id|os-image-id|auto|literal:…\n"
|
||||
" Boot entry token to use for this installation\n"
|
||||
"\nSee the %2$s for details.\n",
|
||||
program_invocation_short_name,
|
||||
link,
|
||||
|
@ -4736,6 +4872,7 @@ static int parse_argv(int argc, char *argv[]) {
|
|||
ARG_PCRLOCK,
|
||||
ARG_POLICY,
|
||||
ARG_FORCE,
|
||||
ARG_ENTRY_TOKEN,
|
||||
};
|
||||
|
||||
static const struct option options[] = {
|
||||
|
@ -4752,6 +4889,7 @@ static int parse_argv(int argc, char *argv[]) {
|
|||
{ "pcrlock", required_argument, NULL, ARG_PCRLOCK },
|
||||
{ "policy", required_argument, NULL, ARG_POLICY },
|
||||
{ "force", no_argument, NULL, ARG_FORCE },
|
||||
{ "entry-token", required_argument, NULL, ARG_ENTRY_TOKEN },
|
||||
{}
|
||||
};
|
||||
|
||||
|
@ -4899,6 +5037,12 @@ static int parse_argv(int argc, char *argv[]) {
|
|||
arg_force = true;
|
||||
break;
|
||||
|
||||
case ARG_ENTRY_TOKEN:
|
||||
r = parse_boot_entry_token_type(optarg, &arg_entry_token_type, &arg_entry_token);
|
||||
if (r < 0)
|
||||
return r;
|
||||
break;
|
||||
|
||||
case '?':
|
||||
return -EINVAL;
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include "alloc-util.h"
|
||||
#include "constants.h"
|
||||
#include "creds-util.h"
|
||||
#include "cryptsetup-util.h"
|
||||
#include "dirent-util.h"
|
||||
#include "dlfcn-util.h"
|
||||
|
@ -25,6 +26,7 @@
|
|||
#include "nulstr-util.h"
|
||||
#include "parse-util.h"
|
||||
#include "random-util.h"
|
||||
#include "recurse-dir.h"
|
||||
#include "sha256.h"
|
||||
#include "sort-util.h"
|
||||
#include "stat-util.h"
|
||||
|
@ -6800,6 +6802,43 @@ int tpm2_pcrlock_search_file(const char *path, FILE **ret_file, char **ret_path)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int tpm2_pcrlock_policy_from_json(
|
||||
JsonVariant *v,
|
||||
Tpm2PCRLockPolicy *ret_policy) {
|
||||
|
||||
/* We use a type check of _JSON_VARIANT_TYPE_INVALID for the integer fields to allow
|
||||
* json_dispatch_uint32() to parse strings as integers to work around the integer type weakness of
|
||||
* JSON's design. */
|
||||
JsonDispatch policy_dispatch[] = {
|
||||
{ "pcrBank", JSON_VARIANT_STRING, json_dispatch_tpm2_algorithm, offsetof(Tpm2PCRLockPolicy, algorithm), JSON_MANDATORY },
|
||||
{ "pcrValues", JSON_VARIANT_ARRAY, json_dispatch_variant, offsetof(Tpm2PCRLockPolicy, prediction_json), JSON_MANDATORY },
|
||||
{ "nvIndex", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint32, offsetof(Tpm2PCRLockPolicy, nv_index), JSON_MANDATORY },
|
||||
{ "nvHandle", JSON_VARIANT_STRING, json_dispatch_unbase64_iovec, offsetof(Tpm2PCRLockPolicy, nv_handle), JSON_MANDATORY },
|
||||
{ "nvPublic", JSON_VARIANT_STRING, json_dispatch_unbase64_iovec, offsetof(Tpm2PCRLockPolicy, nv_public), JSON_MANDATORY },
|
||||
{ "srkHandle", JSON_VARIANT_STRING, json_dispatch_unbase64_iovec, offsetof(Tpm2PCRLockPolicy, srk_handle), JSON_MANDATORY },
|
||||
{ "pinPublic", JSON_VARIANT_STRING, json_dispatch_unbase64_iovec, offsetof(Tpm2PCRLockPolicy, pin_public), JSON_MANDATORY },
|
||||
{ "pinPrivate", JSON_VARIANT_STRING, json_dispatch_unbase64_iovec, offsetof(Tpm2PCRLockPolicy, pin_private), JSON_MANDATORY },
|
||||
{}
|
||||
};
|
||||
|
||||
_cleanup_(tpm2_pcrlock_policy_done) Tpm2PCRLockPolicy policy = {};
|
||||
int r;
|
||||
|
||||
assert(v);
|
||||
assert(ret_policy);
|
||||
|
||||
r = json_dispatch(v, policy_dispatch, JSON_LOG, &policy);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = tpm2_pcr_prediction_from_json(&policy.prediction, policy.algorithm, policy.prediction_json);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*ret_policy = TAKE_STRUCT(policy);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int tpm2_pcrlock_policy_load(
|
||||
const char *path,
|
||||
Tpm2PCRLockPolicy *ret_policy) {
|
||||
|
@ -6816,41 +6855,140 @@ int tpm2_pcrlock_policy_load(
|
|||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to load TPM2 pcrlock policy file: %m");
|
||||
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *configuration_json = NULL;
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
|
||||
r = json_parse_file(
|
||||
f,
|
||||
discovered_path,
|
||||
/* flags = */ 0,
|
||||
&configuration_json,
|
||||
&v,
|
||||
/* ret_line= */ NULL,
|
||||
/* ret_column= */ NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse existing pcrlock policy file '%s': %m", discovered_path);
|
||||
|
||||
JsonDispatch policy_dispatch[] = {
|
||||
{ "pcrBank", JSON_VARIANT_STRING, json_dispatch_tpm2_algorithm, offsetof(Tpm2PCRLockPolicy, algorithm), JSON_MANDATORY },
|
||||
{ "pcrValues", JSON_VARIANT_ARRAY, json_dispatch_variant, offsetof(Tpm2PCRLockPolicy, prediction_json), JSON_MANDATORY },
|
||||
{ "nvIndex", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint32, offsetof(Tpm2PCRLockPolicy, nv_index), JSON_MANDATORY },
|
||||
{ "nvHandle", JSON_VARIANT_STRING, json_dispatch_unbase64_iovec, offsetof(Tpm2PCRLockPolicy, nv_handle), JSON_MANDATORY },
|
||||
{ "nvPublic", JSON_VARIANT_STRING, json_dispatch_unbase64_iovec, offsetof(Tpm2PCRLockPolicy, nv_public), JSON_MANDATORY },
|
||||
{ "srkHandle", JSON_VARIANT_STRING, json_dispatch_unbase64_iovec, offsetof(Tpm2PCRLockPolicy, srk_handle), JSON_MANDATORY },
|
||||
{ "pinPublic", JSON_VARIANT_STRING, json_dispatch_unbase64_iovec, offsetof(Tpm2PCRLockPolicy, pin_public), JSON_MANDATORY },
|
||||
{ "pinPrivate", JSON_VARIANT_STRING, json_dispatch_unbase64_iovec, offsetof(Tpm2PCRLockPolicy, pin_private), JSON_MANDATORY },
|
||||
{}
|
||||
};
|
||||
return tpm2_pcrlock_policy_from_json(v, ret_policy);
|
||||
}
|
||||
|
||||
_cleanup_(tpm2_pcrlock_policy_done) Tpm2PCRLockPolicy policy = {};
|
||||
static int pcrlock_policy_load_credential(
|
||||
const char *name,
|
||||
const struct iovec *data,
|
||||
Tpm2PCRLockPolicy *ret) {
|
||||
|
||||
r = json_dispatch(configuration_json, policy_dispatch, JSON_LOG, &policy);
|
||||
_cleanup_free_ char *c = NULL;
|
||||
int r;
|
||||
|
||||
assert(name);
|
||||
|
||||
c = strdup(name);
|
||||
if (!c)
|
||||
return log_oom();
|
||||
|
||||
ascii_strlower(c); /* Lowercase, to match what we did at encryption time */
|
||||
|
||||
_cleanup_(iovec_done) struct iovec decoded = {};
|
||||
r = decrypt_credential_and_warn(
|
||||
c,
|
||||
now(CLOCK_REALTIME),
|
||||
/* tpm2_device= */ NULL,
|
||||
/* tpm2_signature_path= */ NULL,
|
||||
data,
|
||||
CREDENTIAL_ALLOW_NULL,
|
||||
&decoded);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = tpm2_pcr_prediction_from_json(&policy.prediction, policy.algorithm, policy.prediction_json);
|
||||
if (memchr(decoded.iov_base, 0, decoded.iov_len))
|
||||
return log_error_errno(r, "Credential '%s' contains embedded NUL byte, refusing.", name);
|
||||
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
|
||||
r = json_parse(decoded.iov_base,
|
||||
/* flags= */ 0,
|
||||
&v,
|
||||
/* ret_line= */ NULL,
|
||||
/* ret_column= */ NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse pcrlock policy: %m");
|
||||
|
||||
r = tpm2_pcrlock_policy_from_json(v, ret);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*ret_policy = TAKE_STRUCT(policy);
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tpm2_pcrlock_policy_from_credentials(
|
||||
const struct iovec *srk,
|
||||
const struct iovec *nv,
|
||||
Tpm2PCRLockPolicy *ret) {
|
||||
|
||||
_cleanup_close_ int dfd = -EBADF;
|
||||
int r;
|
||||
|
||||
/* During boot we'll not have access to the pcrlock.json file in /var/. In order to support
|
||||
* pcrlock-bound root file systems we'll store a copy of the JSON data, wrapped in an (plaintext)
|
||||
* credential in the ESP or XBOOTLDR partition. There might be multiple of those however (because of
|
||||
* multi-boot), hence we use the SRK and NV data from the LUKS2 header as search key, and parse all
|
||||
* such JSON policies until we find a matching one. */
|
||||
|
||||
const char *cp = secure_getenv("SYSTEMD_ENCRYPTED_SYSTEM_CREDENTIALS_DIRECTORY") ?: ENCRYPTED_SYSTEM_CREDENTIALS_DIRECTORY;
|
||||
|
||||
dfd = open(cp, O_CLOEXEC|O_DIRECTORY);
|
||||
if (dfd < 0) {
|
||||
if (errno == ENOENT) {
|
||||
log_debug("No encrypted system credentials passed.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return log_error_errno(errno, "Faile to open system credentials directory.");
|
||||
}
|
||||
|
||||
_cleanup_free_ DirectoryEntries *de = NULL;
|
||||
r = readdir_all(dfd, RECURSE_DIR_IGNORE_DOT, &de);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to enumerate system credentials: %m");
|
||||
|
||||
FOREACH_ARRAY(i, de->entries, de->n_entries) {
|
||||
_cleanup_(iovec_done) struct iovec data = {};
|
||||
struct dirent *d = *i;
|
||||
|
||||
if (!startswith_no_case(d->d_name, "pcrlock.")) /* VFAT is case-insensitive, hence don't be too strict here */
|
||||
continue;
|
||||
|
||||
r = read_full_file_full(
|
||||
dfd, d->d_name,
|
||||
/* offset= */ UINT64_MAX,
|
||||
/* size= */ CREDENTIAL_ENCRYPTED_SIZE_MAX,
|
||||
READ_FULL_FILE_UNBASE64|READ_FULL_FILE_FAIL_WHEN_LARGER,
|
||||
/* bind_name= */ NULL,
|
||||
(char**) &data.iov_base,
|
||||
&data.iov_len);
|
||||
if (r == -ENOENT)
|
||||
continue;
|
||||
if (r < 0) {
|
||||
log_warning_errno(r, "Failed to read credentials file %s/%s, skipping: %m", ENCRYPTED_SYSTEM_CREDENTIALS_DIRECTORY, d->d_name);
|
||||
continue;
|
||||
}
|
||||
|
||||
_cleanup_(tpm2_pcrlock_policy_done) Tpm2PCRLockPolicy loaded_policy = {};
|
||||
r = pcrlock_policy_load_credential(
|
||||
d->d_name,
|
||||
&data,
|
||||
&loaded_policy);
|
||||
if (r < 0) {
|
||||
log_warning_errno(r, "Loading of pcrlock policy from credential '%s/%s' failed, skipping.", ENCRYPTED_SYSTEM_CREDENTIALS_DIRECTORY, d->d_name);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((!srk || iovec_memcmp(srk, &loaded_policy.srk_handle) == 0) &&
|
||||
(!nv || iovec_memcmp(nv, &loaded_policy.nv_handle) == 0)) {
|
||||
*ret = TAKE_STRUCT(loaded_policy);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
log_info("No pcrlock policy found among system credentials.");
|
||||
*ret = (Tpm2PCRLockPolicy) {};
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tpm2_load_public_key_file(const char *path, TPM2B_PUBLIC *ret) {
|
||||
|
@ -6970,6 +7108,7 @@ int tpm2_make_luks2_json(
|
|||
const struct iovec *policy_hash,
|
||||
const struct iovec *salt,
|
||||
const struct iovec *srk,
|
||||
const struct iovec *pcrlock_nv,
|
||||
TPM2Flags flags,
|
||||
JsonVariant **ret) {
|
||||
|
||||
|
@ -7012,7 +7151,8 @@ int tpm2_make_luks2_json(
|
|||
JSON_BUILD_PAIR_CONDITION(pubkey_pcr_mask != 0, "tpm2_pubkey_pcrs", JSON_BUILD_VARIANT(pkmj)),
|
||||
JSON_BUILD_PAIR_CONDITION(pubkey_pcr_mask != 0, "tpm2_pubkey", JSON_BUILD_IOVEC_BASE64(pubkey)),
|
||||
JSON_BUILD_PAIR_CONDITION(iovec_is_set(salt), "tpm2_salt", JSON_BUILD_IOVEC_BASE64(salt)),
|
||||
JSON_BUILD_PAIR_CONDITION(iovec_is_set(srk), "tpm2_srk", JSON_BUILD_IOVEC_BASE64(srk))));
|
||||
JSON_BUILD_PAIR_CONDITION(iovec_is_set(srk), "tpm2_srk", JSON_BUILD_IOVEC_BASE64(srk)),
|
||||
JSON_BUILD_PAIR_CONDITION(iovec_is_set(pcrlock_nv), "tpm2_pcrlock_nv", JSON_BUILD_IOVEC_BASE64(pcrlock_nv))));
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -7034,9 +7174,10 @@ int tpm2_parse_luks2_json(
|
|||
struct iovec *ret_policy_hash,
|
||||
struct iovec *ret_salt,
|
||||
struct iovec *ret_srk,
|
||||
struct iovec *ret_pcrlock_nv,
|
||||
TPM2Flags *ret_flags) {
|
||||
|
||||
_cleanup_(iovec_done) struct iovec blob = {}, policy_hash = {}, pubkey = {}, salt = {}, srk = {};
|
||||
_cleanup_(iovec_done) struct iovec blob = {}, policy_hash = {}, pubkey = {}, salt = {}, srk = {}, pcrlock_nv = {};
|
||||
uint32_t hash_pcr_mask = 0, pubkey_pcr_mask = 0;
|
||||
uint16_t primary_alg = TPM2_ALG_ECC; /* ECC was the only supported algorithm in systemd < 250, use that as implied default, for compatibility */
|
||||
uint16_t pcr_bank = UINT16_MAX; /* default: pick automatically */
|
||||
|
@ -7158,6 +7299,13 @@ int tpm2_parse_luks2_json(
|
|||
return log_debug_errno(r, "Invalid base64 data in 'tpm2_srk' field.");
|
||||
}
|
||||
|
||||
w = json_variant_by_key(v, "tpm2_pcrlock_nv");
|
||||
if (w) {
|
||||
r = json_variant_unbase64_iovec(w, &pcrlock_nv);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Invalid base64 data in 'tpm2_pcrlock_nv' field.");
|
||||
}
|
||||
|
||||
if (ret_keyslot)
|
||||
*ret_keyslot = keyslot;
|
||||
if (ret_hash_pcr_mask)
|
||||
|
@ -7176,11 +7324,12 @@ int tpm2_parse_luks2_json(
|
|||
*ret_policy_hash = TAKE_STRUCT(policy_hash);
|
||||
if (ret_salt)
|
||||
*ret_salt = TAKE_STRUCT(salt);
|
||||
if (ret_flags)
|
||||
*ret_flags = flags;
|
||||
if (ret_srk)
|
||||
*ret_srk = TAKE_STRUCT(srk);
|
||||
|
||||
if (ret_pcrlock_nv)
|
||||
*ret_pcrlock_nv = TAKE_STRUCT(pcrlock_nv);
|
||||
if (ret_flags)
|
||||
*ret_flags = flags;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -245,8 +245,10 @@ typedef struct Tpm2PCRLockPolicy {
|
|||
} Tpm2PCRLockPolicy;
|
||||
|
||||
void tpm2_pcrlock_policy_done(Tpm2PCRLockPolicy *data);
|
||||
int tpm2_pcrlock_policy_from_json(JsonVariant *v, Tpm2PCRLockPolicy *ret_policy);
|
||||
int tpm2_pcrlock_search_file(const char *path, FILE **ret_file, char **ret_path);
|
||||
int tpm2_pcrlock_policy_load(const char *path, Tpm2PCRLockPolicy *ret_policy);
|
||||
int tpm2_pcrlock_policy_from_credentials(const struct iovec *srk, const struct iovec *nv, Tpm2PCRLockPolicy *ret);
|
||||
|
||||
int tpm2_index_to_handle(Tpm2Context *c, TPM2_HANDLE index, const Tpm2Handle *session, TPM2B_PUBLIC **ret_public, TPM2B_NAME **ret_name, TPM2B_NAME **ret_qname, Tpm2Handle **ret_handle);
|
||||
int tpm2_index_from_handle(Tpm2Context *c, const Tpm2Handle *handle, TPM2_HANDLE *ret_index);
|
||||
|
@ -383,8 +385,8 @@ int tpm2_find_device_auto(char **ret);
|
|||
int tpm2_make_pcr_json_array(uint32_t pcr_mask, JsonVariant **ret);
|
||||
int tpm2_parse_pcr_json_array(JsonVariant *v, uint32_t *ret);
|
||||
|
||||
int tpm2_make_luks2_json(int keyslot, uint32_t hash_pcr_mask, uint16_t pcr_bank, const struct iovec *pubkey, uint32_t pubkey_pcr_mask, uint16_t primary_alg, const struct iovec *blob, const struct iovec *policy_hash, const struct iovec *salt, const struct iovec *srk, TPM2Flags flags, JsonVariant **ret);
|
||||
int tpm2_parse_luks2_json(JsonVariant *v, int *ret_keyslot, uint32_t *ret_hash_pcr_mask, uint16_t *ret_pcr_bank, struct iovec *ret_pubkey, uint32_t *ret_pubkey_pcr_mask, uint16_t *ret_primary_alg, struct iovec *ret_blob, struct iovec *ret_policy_hash, struct iovec *ret_salt, struct iovec *ret_srk, TPM2Flags *ret_flags);
|
||||
int tpm2_make_luks2_json(int keyslot, uint32_t hash_pcr_mask, uint16_t pcr_bank, const struct iovec *pubkey, uint32_t pubkey_pcr_mask, uint16_t primary_alg, const struct iovec *blob, const struct iovec *policy_hash, const struct iovec *salt, const struct iovec *srk, const struct iovec *pcrlock_nv, TPM2Flags flags, JsonVariant **ret);
|
||||
int tpm2_parse_luks2_json(JsonVariant *v, int *ret_keyslot, uint32_t *ret_hash_pcr_mask, uint16_t *ret_pcr_bank, struct iovec *ret_pubkey, uint32_t *ret_pubkey_pcr_mask, uint16_t *ret_primary_alg, struct iovec *ret_blob, struct iovec *ret_policy_hash, struct iovec *ret_salt, struct iovec *ret_srk, struct iovec *pcrlock_nv, TPM2Flags *ret_flags);
|
||||
|
||||
/* Default to PCR 7 only */
|
||||
#define TPM2_PCR_INDEX_DEFAULT UINT32_C(7)
|
||||
|
|
|
@ -118,7 +118,20 @@ echo -n test70-take-two | "$SD_PCRLOCK" lock-raw --pcrlock=/var/lib/pcrlock.d/92
|
|||
systemd-cryptsetup attach pcrlock "$img" - tpm2-device=auto,tpm2-pcrlock=/var/lib/systemd/pcrlock.json,headless
|
||||
systemd-cryptsetup detach pcrlock
|
||||
|
||||
"$SD_PCRLOCK" remove-policy
|
||||
# Now use the root fs support, i.e. make the tool write a copy of the pcrlock
|
||||
# file as service credential to some temporary dir and remove the local copy, so that
|
||||
# it has to use the credential version.
|
||||
mkdir /tmp/fakexbootldr
|
||||
SYSTEMD_XBOOTLDR_PATH=/tmp/fakexbootldr SYSTEMD_RELAX_XBOOTLDR_CHECKS=1 "$SD_PCRLOCK" make-policy --pcr="$PCRS" --force
|
||||
mv /var/lib/systemd/pcrlock.json /var/lib/systemd/pcrlock.json.gone
|
||||
|
||||
systemd-creds decrypt /tmp/fakexbootldr/loader/credentials/pcrlock.*.cred
|
||||
|
||||
SYSTEMD_ENCRYPTED_SYSTEM_CREDENTIALS_DIRECTORY=/tmp/fakexbootldr/loader/credentials systemd-cryptsetup attach pcrlock "$img" - tpm2-device=auto,headless
|
||||
systemd-cryptsetup detach pcrlock
|
||||
|
||||
mv /var/lib/systemd/pcrlock.json.gone /var/lib/systemd/pcrlock.json
|
||||
SYSTEMD_XBOOTLDR_PATH=/tmp/fakexbootldr SYSTEMD_RELAX_XBOOTLDR_CHECKS=1 "$SD_PCRLOCK" remove-policy
|
||||
|
||||
"$SD_PCRLOCK" unlock-firmware-config
|
||||
"$SD_PCRLOCK" unlock-gpt
|
||||
|
|
Loading…
Reference in a new issue