* Is possible to seal a secret once, and authorize any policy properly signed to unseal it?
@ 2025-12-27 17:39 Felix Rubio
2025-12-28 9:28 ` Felix Rubio
0 siblings, 1 reply; 2+ messages in thread
From: Felix Rubio @ 2025-12-27 17:39 UTC (permalink / raw)
To: tpm2
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
^ permalink raw reply [flat|nested] 2+ messages in thread* Re: Is possible to seal a secret once, and authorize any policy properly signed to unseal it?
2025-12-27 17:39 Is possible to seal a secret once, and authorize any policy properly signed to unseal it? Felix Rubio
@ 2025-12-28 9:28 ` Felix Rubio
0 siblings, 0 replies; 2+ messages in thread
From: Felix Rubio @ 2025-12-28 9:28 UTC (permalink / raw)
To: tpm2
Fixed it, I think, by... carefully looking at the examples. This is my current
flow, now, which seems to work. Sharing in case somebody is interested:
########################################################
#!/bin/bash
set -euf
OUTDIR=/tmp/outdir
SIGN_HANDLE="0x81010021"
mkdir -p "${OUTDIR:?}"
rm -rf "${OUTDIR:?}/*"
############# ONE OFF: CREATE SIGNING KEYS, AUTHORIZED POLICY
AUTH_PRIV="$OUTDIR/auth.priv"
TMPDIR=$(mktemp -d /run/tpm-primary.XXXXXX)
AUTH_PUB="$TMPDIR/auth.pub"
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 -c "$AUTH_PRIMARY_CTX"
tpm2_create -Q -C "$AUTH_PRIMARY_CTX" -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 "$TMPDIR"
############# ONE OFF: CREATE AUTHORIZED POLICY, SEAL THE SECRET
# Seal secret under authorizedPolicy
TMPDIR=$(mktemp -d /run/tpm-seal.XXXXXX)
TPM_CTX="$TMPDIR/tpm.ctx"
AUTHORIZED_POLICY="$TMPDIR/authorized_policy.bin"
echo "[*] Compute authorized policyDigest"
tpm2_startauthsession -Q -S "$TPM_CTX"
tpm2_policyauthorize -Q -S "$TPM_CTX" -n "$OUTDIR/auth.name" -L
"$AUTHORIZED_POLICY"
tpm2_flushcontext -Q "$TPM_CTX"
# Create primary key to seal under, and seal the ZFS key
echo "[*] Seal the secret"
tpm2_createprimary -Q -C o -G rsa -c "$TPM_CTX"
tpm2_create -Q -C "$TPM_CTX" -i- -L "$AUTHORIZED_POLICY" -u "$OUTDIR/
secret.pub" -r "$OUTDIR/secret.priv" <<< "This is my secret"
tpm2_flushcontext -t
rm -rf "$TMPDIR"
############# AFTER UKI UPDATE: SIGN THE NEW PCR VALUES
# Generate signature for PCRS
TMPDIR=$(mktemp -d /run/tpm-pcr-sig.XXXXXX)
SESSION_CTX="$TMPDIR/session.ctx"
POLICY_FILE="$TMPDIR/policy.bin"
echo "[*] Create PCRs signature"
tpm2_startauthsession -S "$SESSION_CTX"
POLICY_HASH=$(tpm2_policypcr -S "$SESSION_CTX" -l sha256:11 -L "$POLICY_FILE")
tpm2_flushcontext "$SESSION_CTX"
tpm2_sign -c "$SIGN_HANDLE" -g sha256 -o "$OUTDIR/policy-$POLICY_HASH.sig"
"$POLICY_FILE"
rm -rf "$TMPDIR"
############# IN INITRAMFS: UNSEAL SECRET
# 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"
tpm2_startauthsession -S "$SESSION_CTX"
POLICY_HASH=$(tpm2_policypcr -S "$SESSION_CTX" -l sha256:11 -L "$POLICY")
tpm2_flushcontext "$SESSION_CTX"
echo "[*] Verifying signature"
tpm2_verifysignature -c "$SIGN_HANDLE" -g sha256 -m "$POLICY" -s "$OUTDIR/
policy-$POLICY_HASH.sig" -t "$TICKET"
echo "[*] Starting policy session"
tpm2_startauthsession --policy-session -S "$SESSION_CTX"
echo "[*] Applying PCR policy"
tpm2_policypcr -Q -S "$SESSION_CTX" -l sha256:11
echo "[*] Authorizing policy"
tpm2_policyauthorize -Q -S "$SESSION_CTX" -i "$POLICY" -n "$OUTDIR/auth.name"
-t "$TICKET"
echo "[*] Loading sealed object"
tpm2_createprimary -Q -C o -c "$PRIMARY_CTX"
tpm2_load -Q -C "$PRIMARY_CTX" -u "$OUTDIR/secret.pub" -r "$OUTDIR/
secret.priv" -c "$ZFSKEY_CTX"
tpm2_flushcontext -Q -t
echo "[*] Unsealing ZFS key"
tpm2_unseal -c "$ZFSKEY_CTX" -p "session:$SESSION_CTX"
tpm2_flushcontext -Q "$SESSION_CTX"
rm -rf "$TMPDIR"
Regards!
On Saturday, 27 December 2025 18:39:37 Central European Standard Time Felix
Rubio wrote:
> 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
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2025-12-28 9:30 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-12-27 17:39 Is possible to seal a secret once, and authorize any policy properly signed to unseal it? Felix Rubio
2025-12-28 9:28 ` Felix Rubio
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox