mirror of
https://github.com/systemd/systemd
synced 2024-10-15 12:34:37 +00:00
measure: allow pre-calculating PCR values for multiple boot phases
This commit is contained in:
parent
40f1856791
commit
6ca0016398
|
@ -156,6 +156,28 @@
|
|||
all suitable TPM2 devices currently discovered.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--phase=</option><replaceable>PHASE</replaceable></term>
|
||||
|
||||
<listitem><para>Controls which boot phase(s) to calculate expected PCR 11 values for. This takes a
|
||||
series of colon-separated strings that encode boot "paths" for entering a specific phase of the boot
|
||||
process. Each of the specified strings is measured by the
|
||||
<filename>systemd-pcrphase-initrd.service</filename> and
|
||||
<citerefentry><refentrytitle>systemd-pcrphase.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
||||
into PCR 11 during different milestones of the boot process. This switch may be specified multiple
|
||||
times to calculate PCR values for multiple boot phases at once. If not used defaults to
|
||||
<literal>enter-initrd</literal>, <literal>enter-initrd:leave-initrd</literal>,
|
||||
<literal>enter-initrd:leave-initrd:ready</literal>, i.e. calculates expected PCR values for the boot
|
||||
phase in the initrd, during early boot, and during system runtime, but excluding the phases before
|
||||
the initrd or when shutting down. This setting is honoured both by <command>calculate</command> and
|
||||
<command>sign</command>. When used with the latter it's particularly useful for generating PCR
|
||||
signatures that can only be used for unlocking resources during specific parts of the boot
|
||||
process.</para>
|
||||
|
||||
<para>For further details about PCR boot phases, see
|
||||
<citerefentry><refentrytitle>systemd-pcrphase.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para></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" />
|
||||
|
|
|
@ -31,11 +31,13 @@ static char *arg_public_key = NULL;
|
|||
static JsonFormatFlags arg_json_format_flags = JSON_FORMAT_PRETTY_AUTO|JSON_FORMAT_COLOR_AUTO|JSON_FORMAT_OFF;
|
||||
static PagerFlags arg_pager_flags = 0;
|
||||
static bool arg_current = false;
|
||||
static char **arg_phase = NULL;
|
||||
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_banks, strv_freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_tpm2_device, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_private_key, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_public_key, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_phase, strv_freep);
|
||||
|
||||
static inline void free_sections(char*(*sections)[_UNIFIED_SECTION_MAX]) {
|
||||
for (UnifiedSection c = 0; c < _UNIFIED_SECTION_MAX; c++)
|
||||
|
@ -63,6 +65,7 @@ static int help(int argc, char *argv[], void *userdata) {
|
|||
" --version Print version\n"
|
||||
" --no-pager Do not pipe output into a pager\n"
|
||||
" -c --current Use current PCR values\n"
|
||||
" --phase=PHASE Specify a boot phase to sign for\n"
|
||||
" --bank=DIGEST Select TPM bank (SHA1, SHA256)\n"
|
||||
" --tpm2-device=PATH Use specified TPM2 device\n"
|
||||
" --private-key=KEY Private key (PEM) to sign with\n"
|
||||
|
@ -89,6 +92,21 @@ static int help(int argc, char *argv[], void *userdata) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static char *normalize_phase(const char *s) {
|
||||
_cleanup_strv_free_ char **l = NULL;
|
||||
|
||||
/* Let's normalize phase expressions. We split the series of colon-separated words up, then remove
|
||||
* all empty ones, and glue them back together again. In other words we remove duplicate ":", as well
|
||||
* as leading and trailing ones. */
|
||||
|
||||
l = strv_split(s, ":"); /* Split series of words */
|
||||
if (!l)
|
||||
return NULL;
|
||||
|
||||
/* Remove all empty words and glue things back together */
|
||||
return strv_join(strv_remove(l, ""), ":");
|
||||
}
|
||||
|
||||
static int parse_argv(int argc, char *argv[]) {
|
||||
enum {
|
||||
ARG_VERSION = 0x100,
|
||||
|
@ -108,6 +126,7 @@ static int parse_argv(int argc, char *argv[]) {
|
|||
ARG_PUBLIC_KEY,
|
||||
ARG_TPM2_DEVICE,
|
||||
ARG_JSON,
|
||||
ARG_PHASE,
|
||||
};
|
||||
|
||||
static const struct option options[] = {
|
||||
|
@ -127,6 +146,7 @@ static int parse_argv(int argc, char *argv[]) {
|
|||
{ "private-key", required_argument, NULL, ARG_PRIVATE_KEY },
|
||||
{ "public-key", required_argument, NULL, ARG_PUBLIC_KEY },
|
||||
{ "json", required_argument, NULL, ARG_JSON },
|
||||
{ "phase", required_argument, NULL, ARG_PHASE },
|
||||
{}
|
||||
};
|
||||
|
||||
|
@ -219,6 +239,20 @@ static int parse_argv(int argc, char *argv[]) {
|
|||
|
||||
break;
|
||||
|
||||
case ARG_PHASE: {
|
||||
char *n;
|
||||
|
||||
n = normalize_phase(optarg);
|
||||
if (!n)
|
||||
return log_oom();
|
||||
|
||||
r = strv_consume(&arg_phase, TAKE_PTR(n));
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case '?':
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -241,14 +275,36 @@ static int parse_argv(int argc, char *argv[]) {
|
|||
if (arg_sections[us])
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "The --current switch cannot be used in combination with --linux= and related switches.");
|
||||
|
||||
if (strv_isempty(arg_phase)) {
|
||||
/* If no phases are specifically selected, pick everything from the beginning of the initrd
|
||||
* to the beginning of shutdown. */
|
||||
if (strv_extend_strv(&arg_phase,
|
||||
STRV_MAKE("enter-initrd",
|
||||
"enter-initrd:leave-initrd",
|
||||
"enter-initrd:leave-initrd:ready"),
|
||||
/* filter_duplicates= */ false) < 0)
|
||||
return log_oom();
|
||||
} else {
|
||||
strv_sort(arg_phase);
|
||||
strv_uniq(arg_phase);
|
||||
}
|
||||
|
||||
_cleanup_free_ char *j = NULL;
|
||||
j = strv_join(arg_phase, ", ");
|
||||
if (!j)
|
||||
return log_oom();
|
||||
|
||||
log_debug("Measuring boot phases: %s", j);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* The PCR 11 state for one specific bank */
|
||||
typedef struct PcrState {
|
||||
char *bank;
|
||||
const EVP_MD *md;
|
||||
void *value;
|
||||
size_t value_size;
|
||||
void *saved_value; /* A copy of the original value we calculated, used by pcr_states_save()/pcr_states_restore() to come later back to */
|
||||
} PcrState;
|
||||
|
||||
static void pcr_state_free_all(PcrState **pcr_state) {
|
||||
|
@ -260,6 +316,7 @@ static void pcr_state_free_all(PcrState **pcr_state) {
|
|||
for (size_t i = 0; (*pcr_state)[i].value; i++) {
|
||||
free((*pcr_state)[i].bank);
|
||||
free((*pcr_state)[i].value);
|
||||
free((*pcr_state)[i].saved_value);
|
||||
}
|
||||
|
||||
*pcr_state = mfree(*pcr_state);
|
||||
|
@ -320,6 +377,8 @@ static int measure_kernel(PcrState *pcr_states, size_t n) {
|
|||
assert(n > 0);
|
||||
assert(pcr_states);
|
||||
|
||||
/* Virtually measures the components of a unified kernel image into PCR 11 */
|
||||
|
||||
if (arg_current) {
|
||||
/* Shortcut things, if we should just use the current PCR value */
|
||||
|
||||
|
@ -432,6 +491,54 @@ static int measure_kernel(PcrState *pcr_states, size_t n) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int measure_phase(PcrState *pcr_states, size_t n, const char *phase) {
|
||||
_cleanup_strv_free_ char **l = NULL;
|
||||
int r;
|
||||
|
||||
assert(pcr_states);
|
||||
assert(n > 0);
|
||||
|
||||
/* Measure a phase string into PCR 11. This splits up the "phase" expression at colons, and then
|
||||
* virtually extends each specified word into PCR 11, to model how during boot we measure a series of
|
||||
* words into PCR 11, one for each phase. */
|
||||
|
||||
l = strv_split(phase, ":");
|
||||
if (!l)
|
||||
return log_oom();
|
||||
|
||||
STRV_FOREACH(word, l) {
|
||||
size_t wl;
|
||||
|
||||
if (isempty(*word))
|
||||
continue;
|
||||
|
||||
wl = strlen(*word);
|
||||
|
||||
for (size_t i = 0; i < n; i++) { /* For each bank */
|
||||
_cleanup_free_ void *b = NULL;
|
||||
int bsz;
|
||||
|
||||
bsz = EVP_MD_size(pcr_states[i].md);
|
||||
assert(bsz > 0);
|
||||
|
||||
b = malloc(bsz);
|
||||
if (!b)
|
||||
return log_oom();
|
||||
|
||||
/* First hash the word itself */
|
||||
if (EVP_Digest(*word, wl, b, NULL, pcr_states[i].md, NULL) != 1)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to hash word '%s'.", *word);
|
||||
|
||||
/* And then extend the PCR with the resulting hash */
|
||||
r = pcr_state_extend(pcr_states + i, b, bsz);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pcr_states_allocate(PcrState **ret) {
|
||||
_cleanup_(pcr_state_free_all) PcrState *pcr_states = NULL;
|
||||
size_t n = 0;
|
||||
|
@ -473,6 +580,39 @@ static int pcr_states_allocate(PcrState **ret) {
|
|||
return (int) n;
|
||||
}
|
||||
|
||||
static int pcr_states_save(PcrState *pcr_states, size_t n) {
|
||||
assert(pcr_states);
|
||||
assert(n > 0);
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
_cleanup_free_ void *saved = NULL;
|
||||
|
||||
if (!pcr_states[i].value)
|
||||
continue;
|
||||
|
||||
saved = memdup(pcr_states[i].value, pcr_states[i].value_size);
|
||||
if (!saved)
|
||||
return log_oom();
|
||||
|
||||
free_and_replace(pcr_states[i].saved_value, saved);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pcr_states_restore(PcrState *pcr_states, size_t n) {
|
||||
assert(pcr_states);
|
||||
assert(n > 0);
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
|
||||
assert(pcr_states[i].value);
|
||||
assert(pcr_states[i].saved_value);
|
||||
|
||||
memcpy(pcr_states[i].value, pcr_states[i].saved_value, pcr_states[i].value_size);
|
||||
}
|
||||
}
|
||||
|
||||
static int verb_calculate(int argc, char *argv[], void *userdata) {
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *w = NULL;
|
||||
_cleanup_(pcr_state_free_all) PcrState *pcr_states = NULL;
|
||||
|
@ -492,36 +632,66 @@ static int verb_calculate(int argc, char *argv[], void *userdata) {
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Save the current state, so that we later can restore to it. This way we can measure the PCR values
|
||||
* for multiple different boot phases without heaving to start from zero each time */
|
||||
r = pcr_states_save(pcr_states, n);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
STRV_FOREACH(phase, arg_phase) {
|
||||
|
||||
r = measure_phase(pcr_states, n, *phase);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
if (arg_json_format_flags & JSON_FORMAT_OFF) {
|
||||
_cleanup_free_ char *hd = NULL;
|
||||
|
||||
if (i == 0) {
|
||||
fflush(stdout);
|
||||
fprintf(stderr, "%s# PCR[%" PRIu32 "] Phase <%s>%s\n",
|
||||
ansi_grey(),
|
||||
TPM_PCR_INDEX_KERNEL_IMAGE,
|
||||
isempty(*phase) ? ":" : *phase,
|
||||
ansi_normal());
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
hd = hexmem(pcr_states[i].value, pcr_states[i].value_size);
|
||||
if (!hd)
|
||||
return log_oom();
|
||||
|
||||
printf("%" PRIu32 ":%s=%s\n", TPM_PCR_INDEX_KERNEL_IMAGE, pcr_states[i].bank, hd);
|
||||
} else {
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *bv = NULL;
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *bv = NULL, *array = NULL;
|
||||
|
||||
array = json_variant_ref(json_variant_by_key(w, pcr_states[i].bank));
|
||||
|
||||
r = json_build(&bv,
|
||||
JSON_BUILD_ARRAY(
|
||||
JSON_BUILD_OBJECT(
|
||||
JSON_BUILD_PAIR_CONDITION(!isempty(*phase), "phase", JSON_BUILD_STRING(*phase)),
|
||||
JSON_BUILD_PAIR("pcr", JSON_BUILD_INTEGER(TPM_PCR_INDEX_KERNEL_IMAGE)),
|
||||
JSON_BUILD_PAIR("hash", JSON_BUILD_HEX(pcr_states[i].value, pcr_states[i].value_size))
|
||||
)
|
||||
)
|
||||
);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to build JSON object: %m");
|
||||
|
||||
r = json_variant_set_field(&w, pcr_states[i].bank, bv);
|
||||
r = json_variant_append_array(&array, bv);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to append JSON object to array: %m");
|
||||
|
||||
r = json_variant_set_field(&w, pcr_states[i].bank, array);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to add bank info to object: %m");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* Return to the original kernel measurement for the next phase calculation */
|
||||
pcr_states_restore(pcr_states, n);
|
||||
}
|
||||
|
||||
if (!FLAGS_SET(arg_json_format_flags, JSON_FORMAT_OFF)) {
|
||||
|
||||
if (arg_json_format_flags & (JSON_FORMAT_PRETTY|JSON_FORMAT_PRETTY_AUTO))
|
||||
|
|
|
@ -69,14 +69,27 @@ if [[ -e /usr/lib/systemd/systemd-measure ]]; then
|
|||
11:sha384=5573f9b2caf55b1d0a6a701f890662d682af961899f0419cf1e2d5ea4a6a68c1f25bd4f5b8a0865eeee82af90f5cb087
|
||||
11:sha512=961305d7e9981d6606d1ce97b3a9a1f92610cac033e9c39064895f0e306abc1680463d55767bd98e751eae115bdef3675a9ee1d29ed37da7885b1db45bb2555b
|
||||
EOF
|
||||
|
||||
/usr/lib/systemd/systemd-measure calculate --linux=/tmp/tpmdata1 --initrd=/tmp/tpmdata2 --bank=sha1 --bank=sha256 --bank=sha384 --bank=sha512 | cmp - /tmp/result
|
||||
/usr/lib/systemd/systemd-measure calculate --linux=/tmp/tpmdata1 --initrd=/tmp/tpmdata2 --bank=sha1 --bank=sha256 --bank=sha384 --bank=sha512 --phase=: | cmp - /tmp/result
|
||||
|
||||
cat >/tmp/result.json <<EOF
|
||||
{"sha1":[{"pcr":11,"hash":"5177e4ad69db92192c10e5f80402bf81bfec8a81"}],"sha256":[{"pcr":11,"hash":"37b48bd0b222394dbe3cceff2fca4660c4b0a90ae9369ec90b42f14489989c13"}],"sha384":[{"pcr":11,"hash":"5573f9b2caf55b1d0a6a701f890662d682af961899f0419cf1e2d5ea4a6a68c1f25bd4f5b8a0865eeee82af90f5cb087"}],"sha512":[{"pcr":11,"hash":"961305d7e9981d6606d1ce97b3a9a1f92610cac033e9c39064895f0e306abc1680463d55767bd98e751eae115bdef3675a9ee1d29ed37da7885b1db45bb2555b"}]}
|
||||
EOF
|
||||
/usr/lib/systemd/systemd-measure calculate --linux=/tmp/tpmdata1 --initrd=/tmp/tpmdata2 --bank=sha1 --bank=sha256 --bank=sha384 --bank=sha512 --phase=: -j | diff -u - /tmp/result.json
|
||||
|
||||
/usr/lib/systemd/systemd-measure calculate --linux=/tmp/tpmdata1 --initrd=/tmp/tpmdata2 --bank=sha1 --bank=sha256 --bank=sha384 --bank=sha512 -j | diff -u - /tmp/result.json
|
||||
cat >/tmp/result <<EOF
|
||||
11:sha1=6765ee305db063040c454d32697d922b3d4f232b
|
||||
11:sha256=21c49c1242042649e09c156546fd7d425ccc3c67359f840507b30be4e0f6f699
|
||||
11:sha384=08d0b003a134878eee552070d51d58abe942f457ca85704131dd36f73728e7327ca837594bc9d5ac7de818d02a3d5dd2
|
||||
11:sha512=65120f6ebc04b156421c6f3d543b2fad545363d9ca61c514205459e9c0e0b22e09c23605eae5853e38458ef3ca54e087168af8d8a882a98d220d9391e48be6d0
|
||||
EOF
|
||||
/usr/lib/systemd/systemd-measure calculate --linux=/tmp/tpmdata1 --initrd=/tmp/tpmdata2 --bank=sha1 --bank=sha256 --bank=sha384 --bank=sha512 --phase=foo | cmp - /tmp/result
|
||||
|
||||
cat >/tmp/result.json <<EOF
|
||||
{"sha1":[{"phase":"foo","pcr":11,"hash":"6765ee305db063040c454d32697d922b3d4f232b"}],"sha256":[{"phase":"foo","pcr":11,"hash":"21c49c1242042649e09c156546fd7d425ccc3c67359f840507b30be4e0f6f699"}],"sha384":[{"phase":"foo","pcr":11,"hash":"08d0b003a134878eee552070d51d58abe942f457ca85704131dd36f73728e7327ca837594bc9d5ac7de818d02a3d5dd2"}],"sha512":[{"phase":"foo","pcr":11,"hash":"65120f6ebc04b156421c6f3d543b2fad545363d9ca61c514205459e9c0e0b22e09c23605eae5853e38458ef3ca54e087168af8d8a882a98d220d9391e48be6d0"}]}
|
||||
EOF
|
||||
/usr/lib/systemd/systemd-measure calculate --linux=/tmp/tpmdata1 --initrd=/tmp/tpmdata2 --bank=sha1 --bank=sha256 --bank=sha384 --bank=sha512 --phase=foo -j | diff -u - /tmp/result.json
|
||||
|
||||
rm /tmp/result /tmp/result.json
|
||||
else
|
||||
echo "/usr/lib/systemd/systemd-measure not found, skipping PCR policy test case"
|
||||
fi
|
||||
|
@ -89,7 +102,7 @@ if [ -e /usr/lib/systemd/systemd-measure ] && \
|
|||
openssl rsa -pubout -in "/tmp/pcrsign-private.pem" -out "/tmp/pcrsign-public.pem"
|
||||
|
||||
# Sign current PCR state with it
|
||||
/usr/lib/systemd/systemd-measure sign --current --bank=sha1 --bank=sha256 --private-key="/tmp/pcrsign-private.pem" --public-key="/tmp/pcrsign-public.pem" | tee "/tmp/pcrsign.sig"
|
||||
/usr/lib/systemd/systemd-measure sign --current --bank=sha1 --bank=sha256 --private-key="/tmp/pcrsign-private.pem" --public-key="/tmp/pcrsign-public.pem" --phase=: | tee "/tmp/pcrsign.sig"
|
||||
dd if=/dev/urandom of=/tmp/pcrtestdata bs=1024 count=64
|
||||
systemd-creds encrypt /tmp/pcrtestdata /tmp/pcrtestdata.encrypted --with-key=host+tpm2-with-public-key --tpm2-public-key="/tmp/pcrsign-public.pem"
|
||||
systemd-creds decrypt /tmp/pcrtestdata.encrypted - --tpm2-signature="/tmp/pcrsign.sig" | cmp - /tmp/pcrtestdata
|
||||
|
@ -99,7 +112,7 @@ if [ -e /usr/lib/systemd/systemd-measure ] && \
|
|||
systemd-creds decrypt /tmp/pcrtestdata.encrypted - --tpm2-signature="/tmp/pcrsign.sig" > /dev/null && { echo 'unexpected success'; exit 1; }
|
||||
|
||||
# Sign new PCR state, decrypting should work now.
|
||||
/usr/lib/systemd/systemd-measure sign --current --bank=sha1 --bank=sha256 --private-key="/tmp/pcrsign-private.pem" --public-key="/tmp/pcrsign-public.pem" > "/tmp/pcrsign.sig2"
|
||||
/usr/lib/systemd/systemd-measure sign --current --bank=sha1 --bank=sha256 --private-key="/tmp/pcrsign-private.pem" --public-key="/tmp/pcrsign-public.pem" --phase=: > "/tmp/pcrsign.sig2"
|
||||
systemd-creds decrypt /tmp/pcrtestdata.encrypted - --tpm2-signature="/tmp/pcrsign.sig2" | cmp - /tmp/pcrtestdata
|
||||
|
||||
# Now, do the same, but with a cryptsetup binding
|
||||
|
@ -121,7 +134,7 @@ if [ -e /usr/lib/systemd/systemd-measure ] && \
|
|||
SYSTEMD_CRYPTSETUP_USE_TOKEN_MODULE=1 /usr/lib/systemd/systemd-cryptsetup attach test-volume2 $img - tpm2-device=auto,tpm2-signature="/tmp/pcrsign.sig2",headless=1 && { echo 'unexpected success'; exit 1; }
|
||||
|
||||
# But once we sign the current PCRs, we should be able to unlock again
|
||||
/usr/lib/systemd/systemd-measure sign --current --bank=sha1 --bank=sha256 --private-key="/tmp/pcrsign-private.pem" --public-key="/tmp/pcrsign-public.pem" > "/tmp/pcrsign.sig3"
|
||||
/usr/lib/systemd/systemd-measure sign --current --bank=sha1 --bank=sha256 --private-key="/tmp/pcrsign-private.pem" --public-key="/tmp/pcrsign-public.pem" --phase=: > "/tmp/pcrsign.sig3"
|
||||
SYSTEMD_CRYPTSETUP_USE_TOKEN_MODULE=0 /usr/lib/systemd/systemd-cryptsetup attach test-volume2 $img - tpm2-device=auto,tpm2-signature="/tmp/pcrsign.sig3",headless=1
|
||||
/usr/lib/systemd/systemd-cryptsetup detach test-volume2
|
||||
SYSTEMD_CRYPTSETUP_USE_TOKEN_MODULE=1 /usr/lib/systemd/systemd-cryptsetup attach test-volume2 $img - tpm2-device=auto,tpm2-signature="/tmp/pcrsign.sig3",headless=1
|
||||
|
|
Loading…
Reference in a new issue