From 9589a8edcaccfbc6fc45c727bd946bd84fb1a07b Mon Sep 17 00:00:00 2001 From: Shahriyar Jalayeri Date: Thu, 23 Nov 2023 11:59:31 +0000 Subject: [PATCH] switch to swtp for running TPM tests Signed-off-by: Shahriyar Jalayeri --- .github/workflows/unit.yml | 3 +- pkg/pillar/evetpm/tpm.go | 61 +++++------ pkg/pillar/evetpm/tpm_test.go | 47 +++++++++ tests/tpm/prep-and-test.sh | 107 ++++++++++++++++++++ tests/tpm/testdata/binary_bios_measurement | Bin 0 -> 52800 bytes tests/tpm/testdata/measurefs_tpm_event_log | Bin 0 -> 2174 bytes tools/tpm-tests-on-qemu.sh | 111 --------------------- 7 files changed, 188 insertions(+), 141 deletions(-) create mode 100755 tests/tpm/prep-and-test.sh create mode 100644 tests/tpm/testdata/binary_bios_measurement create mode 100644 tests/tpm/testdata/measurefs_tpm_event_log delete mode 100644 tools/tpm-tests-on-qemu.sh diff --git a/.github/workflows/unit.yml b/.github/workflows/unit.yml index 746199fd8b..a66212d95a 100644 --- a/.github/workflows/unit.yml +++ b/.github/workflows/unit.yml @@ -23,9 +23,8 @@ jobs: run: | make test - name : Test (TPM Required) - timeout-minutes: 30 run: | - bash tools/tpm-tests-on-qemu.sh + bash tests/tpm/prep-and-test.sh - name: Report test results as Annotations if: ${{ always() }} uses: guyarb/golang-test-annoations@v0.6.0 diff --git a/pkg/pillar/evetpm/tpm.go b/pkg/pillar/evetpm/tpm.go index 002823eafe..ce78a8caba 100644 --- a/pkg/pillar/evetpm/tpm.go +++ b/pkg/pillar/evetpm/tpm.go @@ -27,9 +27,6 @@ import ( ) const ( - //TpmDevicePath is the TPM device file path - TpmDevicePath = "/dev/tpmrm0" - //TpmPasswdHdl is the well known TPM NVIndex for TPM Credentials TpmPasswdHdl tpmutil.Handle = 0x1600000 @@ -72,25 +69,6 @@ const ( //EmptyPassword is an empty string EmptyPassword = "" vaultKeyLength = 32 //Bytes - - // savedSealingPcrsFile is the file that holds a copy of PCR values - // at the time of generating and sealing the disk key into the TPM. - savedSealingPcrsFile = types.PersistStatusDir + "/sealingpcrs" - - // measurementLogSealSuccess is files that holds a copy of event log at the time - // of generating/sealing the disk key into the TPM. - measurementLogSealSuccess = types.PersistStatusDir + "/tpm_measurement_seal_success" - - // measurementLogUnsealFail is files that holds a copy of event log at the time EVE - // fails to unseal the vault key from TPM. - measurementLogUnsealFail = types.PersistStatusDir + "/tpm_measurement_unseal_fail" - - // measurefsTpmEventLog is the file containing the event log from the measure-config - measurefsTpmEventLog = types.PersistStatusDir + "/measurefs_tpm_event_log" - - // measurementLogFile is a kernel exposed variable that contains the - // TPM measurements and events log. - measurementLogFile = "/hostfs/sys/kernel/security/tpm0/binary_bios_measurements" ) // PCRBank256Status stores info about support for @@ -114,6 +92,33 @@ var ( //DiskKeySealingPCRs represents PCRs that we use for sealing DiskKeySealingPCRs = tpm2.PCRSelection{Hash: tpm2.AlgSHA256, PCRs: []int{0, 1, 2, 3, 4, 6, 7, 8, 9, 13, 14}} + + // TpmDevicePath is the TPM device file path, it is not a constant due to + // test usage. + TpmDevicePath = "/dev/tpmrm0" + + // measurementLogFile is a kernel exposed variable that contains the + // TPM measurements and events log. it is not a constant due to test usage. + measurementLogFile = "/hostfs/sys/kernel/security/tpm0/binary_bios_measurements" + + // savedSealingPcrsFile is the file that holds a copy of PCR values at the + // time of generating and sealing the disk key into the TPM. it is not a + // constant due to test usage. + savedSealingPcrsFile = types.PersistStatusDir + "/sealingpcrs" + + // measurementLogSealSuccess is files that holds a copy of event log at the + // time of generating/sealing the disk key into the TPM. it is not a constant + // due to test usage. + measurementLogSealSuccess = types.PersistStatusDir + "/tpm_measurement_seal_success" + + // measurementLogUnsealFail is files that holds a copy of event log at the + // time EVE fails to unseal the vault key from TPM. it is not a constant due + // to test usage. + measurementLogUnsealFail = types.PersistStatusDir + "/tpm_measurement_unseal_fail" + + // measurefsTpmEventLog is the file containing the event log from the measure-config. + // it is not a constant due to test usage. + measurefsTpmEventLog = types.PersistStatusDir + "/measurefs_tpm_event_log" ) // SealedKeyType holds different types of sealed key @@ -641,7 +646,7 @@ func SealDiskKey(log *base.LogObject, key []byte, pcrSel tpm2.PCRSelection) erro } // save a snapshot of current PCR values - if err := saveDiskKeySealingPCRs(savedSealingPcrsFile); err != nil { + if err := saveDiskKeySealingPCRs(); err != nil { log.Warnf("saving snapshot of sealing PCRs failed: %s", err) } @@ -729,7 +734,7 @@ func UnsealDiskKey(pcrSel tpm2.PCRSelection) ([]byte, error) { } // try to find out the mismatching PCR index - mismatch, errPcrMiss := findMismatchingPCRs(savedSealingPcrsFile) + mismatch, errPcrMiss := findMismatchingPCRs() if errPcrMiss != nil { return nil, fmt.Errorf("UnsealWithSession failed: %w, %s, finding mismatching PCR failed: %v", err, evtLogStat, errPcrMiss) } @@ -897,7 +902,7 @@ func copyMeasurementLog(dstPath string) error { return nil } -func saveDiskKeySealingPCRs(pcrsFile string) error { +func saveDiskKeySealingPCRs() error { trw, err := tpm2.OpenTPM(TpmDevicePath) if err != nil { return err @@ -916,11 +921,11 @@ func saveDiskKeySealingPCRs(pcrsFile string) error { return err } - return fileutils.WriteRename(pcrsFile, buff.Bytes()) + return fileutils.WriteRename(savedSealingPcrsFile, buff.Bytes()) } -func findMismatchingPCRs(savedPCRsFile string) ([]int, error) { - frw, err := os.Open(savedPCRsFile) +func findMismatchingPCRs() ([]int, error) { + frw, err := os.Open(savedSealingPcrsFile) if err != nil { return nil, err } diff --git a/pkg/pillar/evetpm/tpm_test.go b/pkg/pillar/evetpm/tpm_test.go index 9deb6e6467..9ef61b1206 100644 --- a/pkg/pillar/evetpm/tpm_test.go +++ b/pkg/pillar/evetpm/tpm_test.go @@ -13,6 +13,7 @@ import ( "reflect" "strings" "testing" + "time" "github.com/google/go-tpm/tpm2" "github.com/google/go-tpm/tpmutil" @@ -23,6 +24,52 @@ import ( var log = base.NewSourceLogObject(logrus.StandardLogger(), "test", 1234) +func TestMain(m *testing.M) { + log.Tracef("Setup test environment") + + // setup variables + TpmDevicePath = "/tmp/eve-tpm/srv.sock" + measurementLogFile = "/tmp/eve-tpm/binary_bios_measurement" + measurefsTpmEventLog = "/tmp/eve-tpm/measurefs_tpm_event_log" + savedSealingPcrsFile = "/tmp/eve-tpm/sealingpcrs" + measurementLogSealSuccess = "/tmp/eve-tpm/tpm_measurement_seal_success" + measurementLogUnsealFail = "/tmp/eve-tpm/tpm_measurement_unseal_fail" + + // check if we are running under the correct context and we end up here + // from tests/tpm/prep-and-test.sh. + _, err := os.Stat(TpmDevicePath) + if err != nil { + log.Warnf("Neither TPM device nor swtpm is available, skipping the test.") + return + } + + // for some reason unknown to me, TPM might return RCRetry for the first + // few operations, so we need to wait for it to become ready. + if err := waitForTpmReadyState(); err != nil { + log.Fatalf("Failed to wait for TPM ready state: %v", err) + } + + m.Run() +} + +func waitForTpmReadyState() error { + for i := 0; i < 10; i++ { + if err := SealDiskKey(log, []byte("secret"), DiskKeySealingPCRs); err != nil { + // this is RCRetry, so retry + if strings.Contains(err.Error(), "code 0x22") { + time.Sleep(100 * time.Millisecond) + continue + } else { + return fmt.Errorf("Something is wrong with the TPM : %w", err) + } + } else { + return nil + } + } + + return fmt.Errorf("TPM did't become ready after 10 attempts, failing the test") +} + func TestSealUnseal(t *testing.T) { _, err := os.Stat(TpmDevicePath) if err != nil { diff --git a/tests/tpm/prep-and-test.sh b/tests/tpm/prep-and-test.sh new file mode 100755 index 0000000000..94bd09920e --- /dev/null +++ b/tests/tpm/prep-and-test.sh @@ -0,0 +1,107 @@ + +#!/bin/bash +# +# Copyright (c) 2023 Zededa, Inc. +# SPDX-License-Identifier: Apache-2.0 + +# add more TPM tests here +TESTS=( + "/pillar/evetpm" + ) + +TPM_SRV_PORT=1337 +TPM_CTR_PORT=$((TPM_SRV_PORT + 1)) +ENDO_SEED=0x4000000B +EK_HANDLE=0x81000001 +SRK_HANDLE=0x81000002 +EVE_TPM_STATE=/tmp/eve-tpm +EVE_TPM_CTRL="$EVE_TPM_STATE/ctrl.sock" +EVE_TPM_SRV="$EVE_TPM_STATE/srv.sock" + +echo "[+] Installing swtpm and tpm2-tools ..." +sudo apt-get -qq update -y > /dev/null +sudo apt-get install swtpm tpm2-tools -y -qq > /dev/null + +echo "[+] preparing the environment ..." +rm -rf $EVE_TPM_STATE +mkdir -p $EVE_TPM_STATE + +flushtpm() { + tpm2 flushcontext -t + tpm2 flushcontext -l + tpm2 flushcontext -s +} + +swtpm socket --tpm2 \ + --server port="$TPM_SRV_PORT" \ + --ctrl type=tcp,port="$TPM_CTR_PORT" \ + --tpmstate dir="$EVE_TPM_STATE" \ + --flags not-need-init,startup-clear & + +PID=$! + +# set Transmission Interface (TCTI) swtpm socket, so tpm2-tools use it +# instead of the default char device interface. +export TPM2TOOLS_TCTI="swtpm:host=localhost,port=$TPM_SRV_PORT" + +# start fresh +tpm2 clear + +# create Endorsement Key +tpm2 createek -c ek.ctx + +# this setup seems very fragile, and quickly errors out with +# "out of memory for object contexts", so flush everything to be safe. +flushtpm + +# create Storage Root Key +tpm2 startauthsession --policy-session -S session.ctx +tpm2 policysecret -S session.ctx -c $ENDO_SEED +tpm2 create -C ek.ctx -P "session:session.ctx" -G rsa2048 -u srk.pub -r srk.priv \ + -a 'restricted|decrypt|fixedtpm|fixedparent|sensitivedataorigin|userwithauth' +tpm2 flushcontext session.ctx +flushtpm + +# load the srk +tpm2 startauthsession --policy-session -S session.ctx +tpm2 policysecret -S session.ctx -c $ENDO_SEED +tpm2 load -C ek.ctx -P "session:session.ctx" -u srk.pub -r srk.priv -c srk.ctx +tpm2 flushcontext session.ctx +flushtpm + +# make persisted know-good-handles out of ek and srk +tpm2 evictcontrol -C o -c ek.ctx $EK_HANDLE +tpm2 evictcontrol -C o -c srk.ctx $SRK_HANDLE + +# clean up +rm session.ctx ek.ctx srk.pub srk.priv srk.ctx + +# just dump persistent handles, good for debugging§ +tpm2 getcap handles-persistent + +# kill swtpm +kill $PID + +# start swtpm again, but this time with unix sockets for tests to use. +# in case we need to debug this, cat the log file. +swtpm socket --tpm2 \ + --flags startup-clear \ + --server type=unixio,path="$EVE_TPM_SRV" \ + --ctrl type=unixio,path="$EVE_TPM_CTRL" \ + --tpmstate dir="$EVE_TPM_STATE" \ + --log file="$EVE_TPM_STATE/swtpm.log"& + +# copy test data, so it is accessible from the go tests +cp "tests/tpm/testdata/binary_bios_measurement" $EVE_TPM_STATE +cp "tests/tpm/testdata/measurefs_tpm_event_log" $EVE_TPM_STATE + +# give swtpm time to start and init the TPM +sleep 1 + +# run tests +echo "[+] Running tests ..." +echo "========================================================" +for T in "${TESTS[@]}"; do + name=$(basename "$T") + cd pkg$T && go test -v -coverprofile="$name.coverage.txt" -covermode=atomic +done diff --git a/tests/tpm/testdata/binary_bios_measurement b/tests/tpm/testdata/binary_bios_measurement new file mode 100644 index 0000000000000000000000000000000000000000..971c7c09f0b349b644322ffb8570656a38fb40a5 GIT binary patch literal 52800 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 literal 0 HcmV?d00001 diff --git a/tests/tpm/testdata/measurefs_tpm_event_log b/tests/tpm/testdata/measurefs_tpm_event_log new file mode 100644 index 0000000000000000000000000000000000000000..b3d75bf50a4e3b42e6466a5b166557c85cb7ac94 GIT binary patch literal 2174 zcmcgtYfx2H6uva3X-UF3K0qA_OfBx^?0w#lj*v=Bg2*^hm@;R-E*CEM;JF6`WXuN> zDmasmCbcMO(jk*fP14kGY|K##AE~9L&;v~I!8qpln8voRChqOp^rzWB&N+Mb`PR4B z`o6Wo9S%n?hhttCe?IBx4PG9aT|90*@P78T(b*Ooo0K%_lM@T;_U+26@wTp7uJTjN zfg9=`+MihJ0fQuJL0aKTd6MnZ-HDkEiCdHHhmD$wuYK|3H-EU5vyHh2190!50sa_Kq-Uq37-~0HN#2>7vIhfp7 zM`o`Z+n=l-JuB zr1p-2Qy1jR`}rjT5u{ zq4>FMZi)Yi?9t`F5`#)`Uxm5@UR60w<#(j0ZS6pHHHBOl5Q}>B&_MW z!jKLns2WrPR8k}zaXn!}(q&x-NY!MBG+FMRyv!{_YIohJlNY44M;5H8TwT5}qyLqW zYv-Se|1vXU>bhm+fp@gH*`0UI=wTkr+v(q|6U^0s5|K0oF-6pXBmjyK08k(bVX~+q zB4`j9n8*e*r~nP#fMr3%P}BsZ8KM-R^HR|~m!C6#a-Upl4!m@9^Uda|sk8UzpMNRq zT9520(CZE4>ZcZ;H6aBqaC(T>fK!A-5vVR3Isr^(kP;DMtYF3+hk%=Ab#tGJK>#!%8S!7TdG?pUtJRy#Li@PE~n@* z9(wQ}rr^-y_NQDH8&DB&u5 zBydmX#A}Be%A(ri9#7tuK4G9Qud6m^@qy}2 /dev/null -sudo apt-get -qq install cloud-image-utils qemu swtpm wget libguestfs-tools > /dev/null - -echo "[+] Downloading the ubuntu qemu image..." -if [ ! -f "$IMG" ]; then - wget -q "https://cloud-images.ubuntu.com/releases/20.04/release/${IMG}" - qemu-img resize "$IMG" +128G > /dev/null -fi - -echo "[+] Setting up image credentials..." -ssh-keygen -q -N '' -f id_rsa -sudo virt-customize --ssh-inject "root:file:id_rsa.pub" --root-password password:whocares -a ${IMG} > /dev/null - -# we need this for some reasons -cat >user-data < /dev/null - sudo apt-get -qq install tpm2-tools > /dev/null - sudo mkdir -p /hostfs/sys/kernel/security/tpm0 - sudo touch /hostfs/sys/kernel/security/tpm0/binary_bios_measurements - sudo mkdir -p /persist/status -EOF - -echo "[+] Preparing the TPM ..." -ssh -q -i id_rsa root@localhost -p 2222 -o "StrictHostKeyChecking no" << EOF - tpm2_clear > /dev/null - tpm2_createprimary -c ek.ctx -C e > /dev/null - tpm2_evictcontrol -c ek.ctx 0x81000001 > /dev/null - tpm2_create -C ek.ctx -G rsa2048 -u srk.pub -r srk.priv -a 'restricted|decrypt|fixedtpm|fixedparent|sensitivedataorigin|userwithauth' > /dev/null - tpm2_load -C ek.ctx -u srk.pub -r srk.priv -c srk.ctx > /dev/null - tpm2_evictcontrol -C o -c srk.ctx 0x81000002 > /dev/null -EOF - -echo "[+] Copying tests to vm ..." -scp -rp -q -i id_rsa -P 2222 -o "StrictHostKeyChecking no" pkg/pillar/ root@localhost:/tmp - -echo "[+] Preparing golang..." -# We want this to expand here, not on the target, so: -# shellcheck disable=SC2087 -ssh -q -i id_rsa root@localhost -p 2222 -o "StrictHostKeyChecking no" << EOF - wget -q "$GOLANG" - rm -rf /usr/local/go && tar -C /usr/local -xzf go1.20.5.linux-amd64.tar.gz -EOF - -echo "[+] Running tests ..." -for T in "${TESTS[@]}"; do - TEST="cd /tmp$T && /usr/local/go/bin/go test -v -coverprofile=coverage.txt -covermode=atomic" - ssh -i id_rsa root@localhost -p 2222 -o "StrictHostKeyChecking no" "$TEST" -done - -echo "[+] Copying code-coverage data..." -for T in "${TESTS[@]}"; do - scp -rp -q -i id_rsa -P 2222 -o "StrictHostKeyChecking no" root@localhost:/tmp"$T"/coverage.txt pkg"$T" -done