Is possible to seal a secret once, and authorize any policy properly signed to unseal it?
Felix Rubio <[email protected]> Sat, 27 Dec 2025 18:39:37 +0100
| Newsgroups | dev.linux.lists.tpm2 |
|---|---|
| Message-ID | <3394779.44csPzL39Z@altair> |
Hi everybody,
I am trying to get a secret sealed once (ZFS encryption key), while being able
to unseal it with any key that is properly signed (so that when I recreate a
UKI I do not have to reseal but just to calculate the new PCR values). I have
played with tpm2-tools across the years, but my knowledge is still quite
basic: I do not know even if this is possible.
This is the script I am using:
########################################################
#!/bin/bash
set -eufx
OUTDIR=/tmp/outdir
SIGN_HANDLE="0x81010021"
mkdir -p "${OUTDIR:?}"
rm -rf "${OUTDIR:?}/*"
#############
# Step 0: Create signing key
AUTH_PUB="$OUTDIR/auth.pub"
AUTH_PRIV="$OUTDIR/auth.priv"
# Create an isolated tmpdir for TPM transient files
TMPDIR=$(mktemp -d /run/tpm-primary.XXXXXX)
AUTH_CTX="$TMPDIR/auth.ctx"
AUTH_PRIMARY_CTX="$TMPDIR/auth_primary.ctx"
# Create a new signing key under a primary key
tpm2_evictcontrol -Q -C o -c "$SIGN_HANDLE" || true
tpm2_createprimary -Q -C o -g 'sha256' -G rsa -c "$AUTH_PRIMARY_CTX"
tpm2_create -Q -C "$AUTH_PRIMARY_CTX" -G rsa -u "$AUTH_PUB" -r "$AUTH_PRIV"
tpm2_load -Q -C "$AUTH_PRIMARY_CTX" -u "$AUTH_PUB" -r "$AUTH_PRIV" -c
"$AUTH_CTX"
tpm2_evictcontrol -Q -C o -c "$AUTH_CTX" "$SIGN_HANDLE"
tpm2_flushcontext -t
# Save Name now that is persistent
tpm2_readpublic -Q -c "$SIGN_HANDLE" -n "$OUTDIR/auth.name"
rm -rf "$AUTH_PUB" "$TMPDIR"
#############
# Step 1: Seal secret under authorizedPolicy using policyRef
TMPDIR=$(mktemp -d /run/tpm-seal.XXXXXX)
TPM_CTX="$TMPDIR/tpm.ctx"
AUTHORIZED_POLICY="$TMPDIR/authorized_policy.bin"
DUMMY_POLICY="$TMPDIR/dummy_policy.bin"
DUMMY_SIG="$TMPDIR/dummy_policy.sig"
echo "[*] Create a dummy policy and sign it"
tpm2_startauthsession -Q --policy-session --hash-algorithm 'sha256' -S
"$TPM_CTX"
tpm2_getpolicydigest -Q -S "$TPM_CTX" -o "$DUMMY_POLICY"
tpm2_flushcontext -Q -s
tpm2_sign -c "$SIGN_HANDLE" -g 'sha256' -d "$DUMMY_POLICY" -o "$DUMMY_SIG"
echo "[*] Compute authorized policyDigest"
tpm2_startauthsession -Q -S "$TPM_CTX"
tpm2_policyauthorize -Q -S "$TPM_CTX" -i "$DUMMY_POLICY" -n "$OUTDIR/
auth.name" -L "$AUTHORIZED_POLICY" < "$DUMMY_SIG"
tpm2_flushcontext -Q -s
# Create primary key to seal under, and seal the ZFS key
echo "[*] Seal the secret"
tpm2_createprimary -Q -C o -g 'sha256' -G rsa -c "$TPM_CTX"
tpm2_create -Q -C "$TPM_CTX" -L "$AUTHORIZED_POLICY" -u "$OUTDIR/secret.pub"
-r "$OUTDIR/secret.priv" <<< "This is my secret"
tpm2_flushcontext -t
rm -rf "$TMPDIR"
#############
# Generate signature for PCRS
TMPDIR=$(mktemp -d /run/tpm-pcr-sig.XXXXXX)
polfile="$TMPDIR/policy.bin"
echo "[*] Create PCRs signature"
POLICY_HASH=$(tpm2_createpolicy --policy-pcr -l sha256:11 -L "$polfile")
tpm2_sign -c "$SIGN_HANDLE" -d "$polfile" -o "$OUTDIR/policy-$POLICY_HASH.sig"
rm -rf "$TMPDIR"
#############
# validate signature for PCRS
TMPDIR=$(mktemp -d /run/tpm-unseal.XXXXXX)
POLICY="$TMPDIR/current_policy.bin"
SESSION_CTX="$TMPDIR/session.ctx"
PRIMARY_CTX="$TMPDIR/primary.ctx"
ZFSKEY_CTX="$TMPDIR/zfskey.ctx"
TICKET="$TMPDIR/verification.tkt"
echo "[*] Get the policy hash"
POLICY_HASH=$(tpm2_createpolicy --policy-pcr -l sha256:11 -L "$POLICY")
echo "[*] Starting policy session"
tpm2_startauthsession --policy-session --hash-algorithm sha256 -S
"$SESSION_CTX"
echo "[*] Verifying signature"
tpm2_verifysignature -c "$SIGN_HANDLE" -d "$POLICY" -s "$OUTDIR/policy-
$POLICY_HASH.sig" -t "$TICKET"
echo "[*] Authorizing policy"
tpm2_policyauthorize -S "$SESSION_CTX" -i "$POLICY" -n "$OUTDIR/auth.name" -t
"$TICKET"
echo "[*] Applying PCR policy"
tpm2_policypcr -S "$SESSION_CTX" -l sha256:11
echo "[*] Loading sealed object"
tpm2_createprimary -Q -C o -g sha256 -G rsa -c "$PRIMARY_CTX"
tpm2_load -Q -C "$PRIMARY_CTX" -u "$OUTDIR/secret.pub" -r "$OUTDIR/
secret.priv" -c "$ZFSKEY_CTX"
echo "[*] Unsealing ZFS key"
tpm2_unseal -c "$ZFSKEY_CTX" -p "session:$SESSION_CTX"
tpm2_flushcontext -Q -s -t
rm -rf "$TMPDIR"
########################################################
What am I doing wrong?
Thank you for any advise you can provide :-) (and happy new year! just in
case...)
--
Felix Rubio