public inbox for tpm2@lists.linux.dev
 help / color / mirror / Atom feed
From: Felix Rubio <felix@kngnt.org>
To: tpm2@lists.linux.dev
Subject: Re: Is possible to seal a secret once, and authorize any policy properly signed to unseal it?
Date: Sun, 28 Dec 2025 10:28:53 +0100	[thread overview]
Message-ID: <2334520.iZASKD2KPV@altair> (raw)
In-Reply-To: <3394779.44csPzL39Z@altair>

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



      reply	other threads:[~2025-12-28  9:30 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
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 message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=2334520.iZASKD2KPV@altair \
    --to=felix@kngnt.org \
    --cc=tpm2@lists.linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox