#!/usr/bin/env bash # For the license, see the LICENSE file in the root directory. #set -x if [ "${SWTPM_TEST_IBMTSS2:-0}" -eq 0 ]; then echo "SWTPM_TEST_IBMTSS2 must be set to run this test." exit 77 fi if ! type -p nvdefinespace startup &>/dev/null; then PREFIX=tss if ! type -p ${PREFIX}nvdefinespace ${PREFIX}startup; then echo "Could not find TPM2 tools (e.g., (tss)startup, (tss)nvdefinespace) in PATH." exit 77 fi fi TOOLSPATH=$(dirname "$(type -P "${PREFIX}startup")") ROOT=${abs_top_builddir:-$(dirname "$0")/..} TESTDIR=${abs_top_testdir:-$(dirname "$0")} TPMDIR="$(mktemp -d)" || exit 1 PID_FILE=$TPMDIR/swtpm.pid SOCK_PATH=$TPMDIR/sock LOGFILE=$TPMDIR/logfile LOGFILE2=$TPMDIR/logfile2 TMPFILE=$TPMDIR/tmpfile BINFILE=$TPMDIR/binfile SIGFILE=$TPMDIR/sigfile STATEFILE=${STATEFILE:-$TPMDIR/state} STORE_PARAM="dir=$TPMDIR" if [ "${SWTPM_TEST_LINEAR_FILE:-0}" -ne 0 ]; then echo "Testing with linear file backend ($STATEFILE)" STORE_PARAM="backend-uri=file://$STATEFILE" fi source "${TESTDIR}/test_common" source "${TESTDIR}/common" skip_test_no_tpm20 "${SWTPM_EXE}" trap "cleanup" SIGTERM EXIT function cleanup() { rm -rf "$TPMDIR" # remove files from tss tools rm -f h01*.bin nvp*.bin if [ -n "$PID" ]; then kill_quiet -SIGTERM "$PID" 2>/dev/null fi } # Fill up the NVRAM space with 2048 bit signing keys and then an NVRAM area that # fills it up to the last byte. We want to make sure that the OBJECTs that the # RSA keys are creating in NVRAM can be loaded into the NVRAM again when the size # of the OBJECT increases when for example the size of the RSA keys increases. # This may force us to increase the NVRAM memory space in libtpms then. function fillup_nvram() { local create="$1" local check="$2" local i sz if [ "$create" -eq 1 ]; then # Fill up the NVRAM space with RSA 2048 keys; # exactly 65 have to fit if ! "${TOOLSPATH}/${PREFIX}createprimary" -hi o -si > "$TMPFILE"; then echo "Error: createprimary failed." exit 1 fi if ! grep -q 80000000 "$TMPFILE"; then echo "Error: createprimary did not result in expected handle 80000000" exit 1 fi for ((i = 0x81000000; i < 0x81000100; i++)); do "${TOOLSPATH}/${PREFIX}evictcontrol" \ -hi o \ -ho 80000000 \ -hp "$(printf "%x" "$i")" &>"$TMPFILE" || break done "${TOOLSPATH}/${PREFIX}getcapability" -cap 1 -pr 81000000 -pc 80 > "$TMPFILE" # We need know we need to see '65 Handles' for state created with # libtpms-0.6.0 and 128kb NVRAM size if ! grep -i "65 Handles" "$TMPFILE"; then echo "Error: Did not find '65 Handles' keyword in output" cat "$TMPFILE" exit 1 fi # Fill up the rest of the NVRAM with a single NVRAM index whose size # we now have to find; # for reference: libtpms v0.6.0 allowed 236 bytes for ((sz = 0; ; sz++)); do "${TOOLSPATH}/${PREFIX}nvdefinespace" \ -hi o \ -ha 01000000 \ -sz "${sz}" > "${TMPFILE}" || break # this worked, so lets remove it and try the next size #echo "NVRAM space of size $sz could be created" "${TOOLSPATH}/${PREFIX}nvundefinespace" \ -hi o \ -ha 01000000 > "${TMPFILE}" done if [ "$sz" -gt 0 ]; then sz=$((sz - 1)) echo "Creating final space of size ${sz}" if ! "${TOOLSPATH}/${PREFIX}nvdefinespace" \ -hi o \ -ha 01000000 \ -sz ${sz} > "${TMPFILE}"; then echo "Error: Could not create final NVRAM space." cat "${TMPFILE}" exit 1 fi fi if [ $sz -eq 0 ]; then echo "Error: NVRAM space could not be created at all; not enough space!" exit 1 elif [ $sz -lt 236 ]; then echo "Error: Insufficient NVRAM memory. Needed to create an NVRAM index with size 236 bytes." exit 1 elif [ $sz -gt 236 ]; then echo "Error: The NVRAM index is too large. Only needed 236 bytes but got $sz bytes." exit 1 else echo "The NVRAM index is exactly of the right size (236 bytes)." fi echo -n "123" > "$BINFILE" if ! "${TOOLSPATH}/${PREFIX}sign" \ -hk 81000000 \ -if "${BINFILE}" \ -os "${SIGFILE}" > "$TMPFILE"; then echo "Error: Could not create signature." cat "$TMPFILE" exit 1 fi fi if [ "$check" -eq 1 ]; then "${TOOLSPATH}/${PREFIX}getcapability" -cap 1 -pr 81000000 -pc 80 > "$TMPFILE" # We need know we need to see '65 Handles' for state created with # libtpms-0.6.0 and 128kb NVRAM size if ! grep -i "65 Handles" "$TMPFILE"; then echo "Error: Did not find '65 Handles' keyword in output" cat "$TMPFILE" exit 1 fi printf "Verifying signature with all the persisted keys\n" echo -n "123" > "$BINFILE" for ((i = 0x81000000; i < 0x81000040; i++)); do if ! "${TOOLSPATH}/${PREFIX}verifysignature" \ -hk "$(printf "%x" "$i")" \ -is "${SIGFILE}" \ -if "${BINFILE}" > "$TMPFILE"; then echo "Verifying signature failed for handle $(printf "%x" "$i")." exit 1 fi done fi } export TPM_SERVER_TYPE=raw export TPM_SERVER_NAME=127.0.0.1 export TPM_INTERFACE_TYPE=socsim export TPM_COMMAND_PORT=${TPM_COMMAND_PORT:-65460} export TPM_DATA_DIR=$TPMDIR export TPM_SESSION_ENCKEY="807e2bfe898ddaed8fa6310e716a24dc" # for sessions $SWTPM_EXE socket \ --server "port=${TPM_COMMAND_PORT}" \ --tpmstate "$STORE_PARAM" \ --pid "file=$PID_FILE" \ --ctrl "type=unixio,path=$SOCK_PATH" \ --log "file=$LOGFILE,level=20" \ --tpm2 \ ${SWTPM_TEST_SECCOMP_OPT:+${SWTPM_TEST_SECCOMP_OPT}} & if wait_for_file "$PID_FILE" 3; then echo "Error: (1) Socket TPM did not write pidfile." exit 1 fi PID="$(cat "$PID_FILE")" # Send TPM_Init if ! act=$($SWTPM_IOCTL --unix "$SOCK_PATH" -i 2>&1); then echo "Error: $SWTPM_IOCTL CMD_INIT failed: $act" exit 1 fi if ! "${TOOLSPATH}/${PREFIX}startup" -c; then echo "Error: tpm_startup clear failed." exit 1 fi fillup_nvram 1 1 # Send Shutdown if ! act=$($SWTPM_IOCTL --unix "$SOCK_PATH" -s 2>&1); then echo "Error: $SWTPM_IOCTL CMD_SHUTDOWN failed: $act" exit 1 fi if wait_process_gone "${PID}" 4; then echo "Error: swtpm did not shut down" exit 1 fi echo "============================" >> "$LOGFILE" echo "TPM was shut down" # Store this state for later usage; use a really old version of libtpms: 0.6.0 #cp $TPMDIR/tpm2-00.permall ${TESTDIR}/data/tpm2state5; #cp $SIGFILE ${TESTDIR}/data/tpm2state5/signature.bin ################################################################# # Run TPM2 with the created state and verify it's the same $SWTPM_EXE socket \ --server "port=${TPM_COMMAND_PORT}" \ --tpmstate "$STORE_PARAM" \ --pid "file=$PID_FILE" \ --ctrl "type=unixio,path=$SOCK_PATH" \ --log "file=$LOGFILE,level=20" \ --tpm2 \ ${SWTPM_TEST_SECCOMP_OPT:+${SWTPM_TEST_SECCOMP_OPT}} & if wait_for_file "$PID_FILE" 3; then echo "Error: (2) Socket TPM did not write pidfile." exit 1 fi echo "TPM re-started" PID="$(cat "$PID_FILE")" # Send TPM_Init if ! act=$($SWTPM_IOCTL --unix "$SOCK_PATH" -i 2>&1); then echo "Error: $SWTPM_IOCTL CMD_INIT failed: $act" cat "$LOGFILE" exit 1 fi if ! "${TOOLSPATH}/${PREFIX}startup" -c; then echo "Error: tpm_startup clear failed." cat "$LOGFILE" exit 1 fi fillup_nvram 0 1 if ! "${TOOLSPATH}/${PREFIX}shutdown" -c; then echo "Error: tpm_shutdown clear failed." cat "$LOGFILE" exit 1 fi # Send Shutdown if ! act=$($SWTPM_IOCTL --unix "$SOCK_PATH" -s 2>&1); then echo "Error: $SWTPM_IOCTL CMD_SHUTDOWN failed: $act" exit 1 fi echo "============================" >> "$LOGFILE" echo "TPM was shut down" ################################################################# # Run TPM2 with previously saved state and verify it's the same if [ "${SWTPM_TEST_LINEAR_FILE:-0}" -ne 0 ]; then echo "Test 1 OK (skipped last with linear file)" exit 0 fi rm -f "$TPMDIR"/* cp -f "${TESTDIR}/data/tpm2state5/tpm2-00.permall" "$TPMDIR/tpm2-00.permall" cp "${TESTDIR}/data/tpm2state5/signature.bin" "$SIGFILE" $SWTPM_EXE socket \ --server "port=${TPM_COMMAND_PORT}" \ --tpmstate "$STORE_PARAM,lock" \ --pid "file=$PID_FILE" \ --ctrl "type=unixio,path=$SOCK_PATH" \ --log "file=$LOGFILE,level=20" \ --tpm2 \ ${SWTPM_TEST_SECCOMP_OPT:+${SWTPM_TEST_SECCOMP_OPT}} & if wait_for_file "$PID_FILE" 3; then echo "Error: (3) Socket TPM did not write pidfile." exit 1 fi echo "TPM started with previously generated state" PID="$(cat "$PID_FILE")" # Send TPM_Init if ! act=$($SWTPM_IOCTL --unix "$SOCK_PATH" -i 2>&1); then echo "Error: $SWTPM_IOCTL CMD_INIT failed: $act" exit 1 fi if ! "${TOOLSPATH}/${PREFIX}startup" -c; then echo "Error: tpm_startup clear failed." cat "$LOGFILE" exit 1 fi fillup_nvram 0 1 if ! "${TOOLSPATH}/${PREFIX}shutdown" -c; then echo "Error: tpm_shutdown clear failed." cat "$LOGFILE" exit 1 fi # Start another swtpm that must fail to start due to locked storage # The not-need-init flag causes the failure. if $SWTPM_EXE socket \ --tpmstate "$STORE_PARAM,lock" \ --log "file=${LOGFILE2},level=1" \ --flags not-need-init \ --tpm2 \ ${SWTPM_TEST_SECCOMP_OPT:+${SWTPM_TEST_SECCOMP_OPT}}; then echo "Error: Starting 2nd instance on locked storage should have failed" exit 1 fi if ! grep -q "Resource temporarily unavailable" "${LOGFILE2}"; then echo "Error: Expected error 'Resource temporarily unavailable' in logfile" cat "${LOGFILE2}" exit 1 fi # Send Shutdown if ! act=$($SWTPM_IOCTL --unix "$SOCK_PATH" -s 2>&1); then echo "Error: $SWTPM_IOCTL CMD_SHUTDOWN failed: $act" exit 1 fi echo "Test 1 OK"