Skip to content

Commit

Permalink
pxe-server: seal TK with policy to prevent reuse (#121)
Browse files Browse the repository at this point in the history
This creates a policy so that the TK can only be unsealed
if PCR11 (`$POLICY_PCR`) is zero.  Once the TK has been used,
the `bootscript` extends PCR11 so that it is no longer possible
to use the TK.

This also renamed the `wrapper.pub` key to `transport.pub`
to be the same as the documentation.
  • Loading branch information
osresearch committed Jun 9, 2021
1 parent 52475c2 commit 44aa3ab
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 31 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,5 @@ local.conf
*.gz
build
linux-*
initramfs/response/wrapper.*
initramfs/response/transport.*
initramfs/response/*.hash
47 changes: 37 additions & 10 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,7 @@ BOOTX64=build/boot/EFI/BOOT/BOOTX64.EFI
$(BOOTX64): build/vmlinuz initramfs/cmdline.txt bin/sbsign.safeboot build/signing.key build/initrd.cpio.xz
mkdir -p "$(dir $@)"
DIR=. \
bash -x ./sbin/safeboot unify-kernel \
./sbin/safeboot unify-kernel \
$@.tmp \
linux=build/vmlinuz \
initrd=build/initrd.cpio.xz \
Expand Down Expand Up @@ -455,6 +455,24 @@ $(TPMDIR)/ek.pub: | $(SWTPM) bin/tpm2 build
kill `cat "$(TPMDIR)/swtpm-ek.pid"`
@-$(RM) "$(TPMDIR)/swtpm-ek.pid"

tpm-shell: $(SWTPM)
$(SWTPM) socket \
--tpm2 \
--flags startup-clear \
--tpmstate dir="$(TPMDIR)" \
--server type=tcp,port=9998 \
--ctrl type=tcp,port=9999 \
--pid file="$(TPMDIR)/swtpm-ek.pid" &
sleep 1

TPM2TOOLS_TCTI=swtpm:host=localhost,port=9998 \
LD_LIBRARY_PATH=`pwd`/tpm2-tss/src/tss2-tcti/.libs/ \
PATH=`pwd`/bin:`pwd`/sbin:$(PATH) \
bash

kill `cat "$(TPMDIR)/swtpm-ek.pid"`
@-$(RM) "$(TPMDIR)/swtpm-ek.pid"

# Convert an EK PEM formatted public key into the hash of the modulus,
# which is used by the quote and attestation server to identify the machine
# none of the tools output this easily, so do lots of text manipulation to make it
Expand All @@ -466,7 +484,7 @@ $(TPMDIR)/ek.hash: $(TPMDIR)/ek.pub | build
# Register the virtual TPM in the attestation server logs with the
# expected value for the kernel that will be booted

$(TPMDIR)/.ekpub.registered: $(TPMDIR)/ek.pub initramfs/response/* initramfs/response/rootfs.enc.key initramfs/response/img.hash | build
$(TPMDIR)/.ekpub.registered: $(TPMDIR)/ek.pub initramfs/response/* initramfs/response/rootfs.enc.key initramfs/response/transport.seed initramfs/response/img.hash | build
tar \
-zcf - \
-C initramfs/response \
Expand All @@ -479,25 +497,34 @@ $(TPMDIR)/.ekpub.registered: $(TPMDIR)/ek.pub initramfs/response/* initramfs/res

# Generate a device specific RSA key and create a TPM2 duplicate structure
# so that only the destination device can use it with their TPM
initramfs/response/wrapper.seed: $(TPMDIR)/ek.pub | bin/tpm2
openssl genrsa -out build/wrapper-priv.pem
openssl rsa -in build/wrapper-priv.pem -pubout -out build/wrapper-pub.pem
# Set the policy so that it is only valid if PCR11 is 0
initramfs/response/transport.seed: $(TPMDIR)/ek.pub | bin/tpm2
openssl genrsa -out build/transport-priv.pem
openssl rsa \
-pubout \
-in build/transport-priv.pem \
-out build/transport-pub.pem \

echo -n 'fd32fa22c52cfc8e1a0c29eb38519f87084cab0b04b0d8f020a4d38b2f4e223e' \
| xxd -p -r > $(TPMDIR)/policy.dat

./bin/tpm2 duplicate \
--tcti none \
-U $< \
-G rsa \
-k build/wrapper-priv.pem \
-u $(dir $@)wrapper.pub \
-r $(dir $@)wrapper.dpriv \
-L "$(TPMDIR)/policy.dat" \
-k build/transport-priv.pem \
-u $(dir $@)transport.pub \
-r $(dir $@)transport.dpriv \
-s $(@)

# encrypt the disk encryption key with the seed key so that only the destination
# machine can decrypt it using a TPM duplicate key
initramfs/response/rootfs.enc.key: initramfs/response/wrapper.seed
initramfs/response/rootfs.enc.key: initramfs/response/transport.seed
echo magicwords | openssl rsautl \
-encrypt \
-pubin \
-inkey build/wrapper-pub.pem \
-inkey build/transport-pub.pem \
-out $@

# QEMU tries to boot from the DVD and HD before finally booting from the
Expand Down
63 changes: 43 additions & 20 deletions initramfs/bootscript
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@
# will be passed on the command line

#set -x
die() { echo >&2 "$@" ; exit 1 ; }
POLICY_PCR=11
die() {
echo >&2 "$@"
echo "FAILED" | tpm2 pcrevent $POLICY_PCR
exit 1
}
warn() { echo >&2 "$@" ; }

DEV="/dev/sda"
Expand Down Expand Up @@ -35,51 +40,69 @@ tpm2_ek_session() {
tpm2 flushcontext -t
tpm2 flushcontext -s
tpm2 startauthsession \
--session session.ctx \
--session "ek-session.ctx" \
--policy-session \
|| die "tpm2: unable to start policy session"
tpm2 policysecret \
--session session.ctx \
--session "ek-session.ctx" \
--object-context endorsement \
|| die "tpm2: unable to set policysecret for endorsement hierarchy"
}
tpm2_tk_session() {
tpm2 startauthsession \
--session "tk-session.ctx" \
--policy-session \
|| die "tpm2: unable to start tk-policy session"
tpm2 policypcr \
--session "tk-session.ctx" \
--policy "tk-policy.dat" \
--pcr-list="sha256:$POLICY_PCR" \
|| die "tpm2: unable to load policy pcr"
}

if [ -r "$TMPDIR/wrapper.seed" ]; then
if [ -r "$TMPDIR/transport.seed" ]; then
# attempt to load the secret wrapping key into our TPM
# as a transient object
tpm2 createek \
--ek-context ek.ctx \
|| die "tpm2: unable to create ek object"

warn "tpm2: Importing duplicate wrapper key"
warn "tpm2: Importing duplicate transport key"
tpm2_ek_session

tpm2 import \
--parent-context ek.ctx \
--parent-auth session:session.ctx \
--parent-auth "session:ek-session.ctx" \
--key-algorithm rsa \
--input "$TMPDIR/wrapper.dpriv" \
--seed "$TMPDIR/wrapper.seed" \
--public "$TMPDIR/wrapper.pub" \
--private "$TMPDIR/wrapper.priv" \
|| die "tpm2: unable to import duplicate wrapper key object"
--input "$TMPDIR/transport.dpriv" \
--seed "$TMPDIR/transport.seed" \
--public "$TMPDIR/transport.pub" \
--private "$TMPDIR/transport.priv" \
|| die "tpm2: unable to import duplicate transport key object"

warn "tpm2: Loading duplicate wrapper key"
warn "tpm2: Loading duplicate transport key"
tpm2_ek_session
tpm2 load \
--parent-context ek.ctx \
--auth session:session.ctx \
--key-context "$TMPDIR/wrapper.ctx" \
--public "$TMPDIR/wrapper.pub" \
--private "$TMPDIR/wrapper.priv" \
|| die "tpm2: unable to load duplicate wrapper key object"
--auth "session:ek-session.ctx" \
--key-context "$TMPDIR/transport.ctx" \
--public "$TMPDIR/transport.pub" \
--private "$TMPDIR/transport.priv" \
|| die "tpm2: unable to load duplicate transport key object"

# attempt to decrypt the rootfs key with the wrapper key
# attempt to decrypt the rootfs key with the transport key
warn "tpm2: Decrypting rootfs key"
tpm2_tk_session
tpm2 rsadecrypt \
--key-context "$TMPDIR/wrapper.ctx" \
--auth "session:tk-session.ctx" \
--key-context "$TMPDIR/transport.ctx" \
< "$TMPDIR/rootfs.enc.key" \
> "$TMPDIR/rootfs.key" \
|| die "tpm2: unable to decrypt the rootfs key with wrapper key"
|| die "tpm2: unable to decrypt the rootfs key with transport key"

# extend PCR11 so that the policy can not be satisfied
echo "UNLOCKED" | tpm2 pcrevent "$POLICY_PCR" \
|| die "tmp2: unable to extend PCR$POLICY_PCR"
fi

kexec_img() {
Expand Down

0 comments on commit 44aa3ab

Please sign in to comment.