diff --git a/.gitignore b/.gitignore index 2fe92828..52f352d5 100644 --- a/.gitignore +++ b/.gitignore @@ -44,5 +44,5 @@ local.conf *.gz build linux-* -initramfs/response/wrapper.* +initramfs/response/transport.* initramfs/response/*.hash diff --git a/Makefile b/Makefile index ac0bb1ea..3423b710 100644 --- a/Makefile +++ b/Makefile @@ -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 \ @@ -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 @@ -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 \ @@ -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 diff --git a/initramfs/bootscript b/initramfs/bootscript index f15a29f6..c31b6e23 100755 --- a/initramfs/bootscript +++ b/initramfs/bootscript @@ -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" @@ -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() {