diff --git a/.github/workflows/install-dependencies b/.github/workflows/install-dependencies index 9ffeffd2..c5e34f6a 100755 --- a/.github/workflows/install-dependencies +++ b/.github/workflows/install-dependencies @@ -24,7 +24,7 @@ debian:*|ubuntu:*) build-essential pkg-config libssl-dev libjansson-dev libjose-dev \ luksmeta libluksmeta-dev libpwquality-tools libglib2.0-dev \ libudisks2-dev libaudit-dev systemd opensc pcscd libsofthsm2-dev \ - swtpm-tools tpm-tools; do + swtpm-tools tpm-tools tpm2-tools; do sleep 5 done ;; diff --git a/src/pins/tpm2/meson.build b/src/pins/tpm2/meson.build index ec01dcf9..19077106 100644 --- a/src/pins/tpm2/meson.build +++ b/src/pins/tpm2/meson.build @@ -11,25 +11,7 @@ if all bins += join_paths(meson.current_source_dir(), 'clevis-decrypt-tpm2') bins += join_paths(meson.current_source_dir(), 'clevis-encrypt-tpm2') mans += join_paths(meson.current_source_dir(), 'clevis-encrypt-tpm2.1') + subdir('tests') else warning('Will not install tpm2 pin due to missing dependencies!') endif - -# Tests. -env = environment() -env.prepend('PATH', - join_paths(meson.source_root(), 'src'), - join_paths(meson.source_root(), 'src', 'luks'), - join_paths(meson.source_root(), 'src', 'luks', 'tests'), - join_paths(meson.source_root(), 'src', 'pins', 'sss'), - join_paths(meson.source_root(), 'src', 'pins', 'tang'), - join_paths(meson.source_root(), 'src', 'pins', 'tpm2'), - join_paths(meson.build_root(), 'src'), - join_paths(meson.build_root(), 'src', 'luks'), - join_paths(meson.build_root(), 'src', 'luks', 'tests'), - join_paths(meson.build_root(), 'src', 'pins', 'sss'), - join_paths(meson.build_root(), 'src', 'pins', 'tang'), - join_paths(meson.build_root(), 'src', 'pins', 'tpm2'), - separator: ':' -) -test('pin-tpm2', find_program('pin-tpm2'), env: env, timeout: 120) diff --git a/src/pins/tpm2/tests/meson.build b/src/pins/tpm2/tests/meson.build new file mode 100644 index 00000000..e49ff37a --- /dev/null +++ b/src/pins/tpm2/tests/meson.build @@ -0,0 +1,21 @@ +# Tests. +env = environment() +env.prepend('PATH', + join_paths(meson.source_root(), 'src'), + join_paths(meson.source_root(), 'src', 'luks'), + join_paths(meson.source_root(), 'src', 'luks', 'tests'), + join_paths(meson.source_root(), 'src', 'pins', 'sss'), + join_paths(meson.source_root(), 'src', 'pins', 'tang'), + join_paths(meson.source_root(), 'src', 'pins', 'tpm2'), + join_paths(meson.source_root(), 'src', 'pins', 'tpm2', 'tests'), + join_paths(meson.build_root(), 'src'), + join_paths(meson.build_root(), 'src', 'luks'), + join_paths(meson.build_root(), 'src', 'luks', 'tests'), + join_paths(meson.build_root(), 'src', 'pins', 'sss'), + join_paths(meson.build_root(), 'src', 'pins', 'tang'), + join_paths(meson.build_root(), 'src', 'pins', 'tpm2'), + join_paths(meson.build_root(), 'src', 'pins', 'tpm2', 'tests'), + separator: ':' +) +test('pin-tpm2-hw', find_program('pin-tpm2-hw'), env: env, timeout: 120) +test('pin-tpm2-sw', find_program('pin-tpm2-sw'), env: env, timeout: 120) diff --git a/src/pins/tpm2/tests/pin-tpm2-hw b/src/pins/tpm2/tests/pin-tpm2-hw new file mode 100755 index 00000000..2c444d13 --- /dev/null +++ b/src/pins/tpm2/tests/pin-tpm2-hw @@ -0,0 +1,26 @@ +#!/bin/bash -x +# vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: +# +# Copyright (c) 2019 Red Hat, Inc. +# Author: Sergio Correia +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +. tpm2-common-test-functions + +tpm2_hw_available || skip_test +tpm2_version || skip_test + +. pin-tpm2-tests diff --git a/src/pins/tpm2/tests/pin-tpm2-sw b/src/pins/tpm2/tests/pin-tpm2-sw new file mode 100755 index 00000000..8b64c136 --- /dev/null +++ b/src/pins/tpm2/tests/pin-tpm2-sw @@ -0,0 +1,27 @@ +#!/bin/bash -x +# vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: +# +# Copyright (c) 2019 Red Hat, Inc. +# Author: Sergio Correia +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +. tpm2-common-test-functions + +tpm2_sw_check_preconditions +tpm2_version || skip_test +tpm2_start_emulation + +. pin-tpm2-tests diff --git a/src/pins/tpm2/pin-tpm2 b/src/pins/tpm2/tests/pin-tpm2-tests similarity index 74% rename from src/pins/tpm2/pin-tpm2 rename to src/pins/tpm2/tests/pin-tpm2-tests index 05f0649a..c4172780 100755 --- a/src/pins/tpm2/pin-tpm2 +++ b/src/pins/tpm2/tests/pin-tpm2-tests @@ -20,43 +20,6 @@ TEST=$(basename "${0}") -# Code to return to mark test as skipped. -SKIP_RET_CODE=77 - -tpm2_available() { - # Old environment variables for tpm2-tools 3.0 - export TPM2TOOLS_TCTI_NAME=device - export TPM2TOOLS_DEVICE_FILE= - for dev in /dev/tpmrm?; do - [ -e "${dev}" ] || continue - TPM2TOOLS_DEVICE_FILE="${dev}" - break - done - - # New environment variable for tpm2-tools >= 3.1 - export TPM2TOOLS_TCTI="${TPM2TOOLS_TCTI_NAME}:${TPM2TOOLS_DEVICE_FILE}" - - if [ -z "${TPM2TOOLS_DEVICE_FILE}" ]; then - echo "A TPM2 device with the in-kernel resource manager is needed!" >&2 - return 1 - fi - - if ! [[ -r "${TPM2TOOLS_DEVICE_FILE}" \ - && -w "${TPM2TOOLS_DEVICE_FILE}" ]]; then - echo "The ${TPM2TOOLS_DEVICE_FILE} device must be readable and writable!" >&2 - return 1 - fi - - local _tpm2tools_info="$(tpm2_createprimary -v)" - local _match='version="(.)\.' - [[ ${_tpm2tools_info} =~ ${_match} ]] && TPM2TOOLS_VERSION="${BASH_REMATCH[1]}" - if [[ $TPM2TOOLS_VERSION -lt 3 ]] || [[ $TPM2TOOLS_VERSION -gt 5 ]]; then - echo "The tpm2 pin requires a tpm2-tools version between 3 and 5" >&2 - return 1 - fi - export TPM2TOOLS_VERSION -} - validate_pcrs() { local _pcr_bank="${1}" local _pcrs="${2}" @@ -77,11 +40,6 @@ validate_pcrs() { return 0 } -# Checking if we can run this test. -if ! tpm2_available; then - exit ${SKIP_RET_CODE} -fi - decode_jwe() { local jwe="${1}" @@ -158,32 +116,17 @@ else fi # Test with policies if we have the PIN rewrite available -if ! $(which clevis-pin-tpm2 >/dev/null 2>&1); +if ! command -v clevis-pin-tpm2 >/dev/null 2>&1; then echo "No PIN rewrite available" exit 0 fi -if ! $(which clevis-pin-tpm2-signtool >/dev/null 2>&1); +if ! command -v clevis-pin-tpm2-signtool >/dev/null 2>&1; then echo "No policy signtool available" exit 0 fi -function on_exit() { - popd - if [ ! -d "$TMP" ] || ! rm -rf "$TMP"; then - echo "Delete temporary files failed!" >&2 - echo "You need to clean up: $TMP" >&2 - exit 1 - fi -} -if ! TMP="$(mktemp -d)"; then - echo "Creating a temporary dir for TPM files failed!" >&2 - exit 1 -fi -trap 'on_exit' EXIT -pushd $TMP - clevis-pin-tpm2-signtool >policy_working.json << EOP --- - policy_ref: diff --git a/src/pins/tpm2/tests/tpm2-common-test-functions b/src/pins/tpm2/tests/tpm2-common-test-functions new file mode 100644 index 00000000..076189c2 --- /dev/null +++ b/src/pins/tpm2/tests/tpm2-common-test-functions @@ -0,0 +1,124 @@ +#!/bin/bash -x +# vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: +# +# Copyright (c) 2019 Red Hat, Inc. +# Author: Sergio Correia +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +. tests-common-functions + +SWTPM_BIN="$(command -v swtpm || echo /usr/bin/swtpm)" +SWTPM_SETUP_BIN="$(command -v swtpm_setup || echo /usr/bin/swtpm_setup)" +SWTPM_BIOS_BIN="$(command -v swtpm_bios || echo /usr/bin/swtpm_bios)" + +SWTPM_SOCKET_PID= + +function on_exit() { + popd || error "Unable to change directory" + if [ ! -d "$TESTDIR" ] || ! rm -rf "$TESTDIR"; then + echo "Delete temporary files failed!" >&2 + echo "You need to clean up: $TESTDIR" >&2 + exit 1 + fi + + # Cleanup sw emulation + if [ -n "$SWTPM_SOCKET_PID" ]; then + kill $SWTPM_SOCKET_PID >/dev/null 2>&1 + sleep .5 + # swtpm does not always terminate gracefully, so kill it + kill -9 $SWTPM_SOCKET_PID >/dev/null 2>&1 + fi +} +if ! TESTDIR="$(mktemp -d)"; then + echo "Creating a temporary dir for TPM files failed!" >&2 + exit 1 +fi +trap 'on_exit' EXIT +pushd "$TESTDIR" || error "Unable to change directory" + + +tpm2_hw_available() { + # Old environment variables for tpm2-tools 3.0 + export TPM2TOOLS_TCTI_NAME=device + export TPM2TOOLS_DEVICE_FILE= + for dev in /dev/tpmrm?; do + [ -e "${dev}" ] || continue + TPM2TOOLS_DEVICE_FILE="${dev}" + break + done + + # New environment variable for tpm2-tools >= 3.1 + export TPM2TOOLS_TCTI="${TPM2TOOLS_TCTI_NAME}:${TPM2TOOLS_DEVICE_FILE}" + + if [ -z "${TPM2TOOLS_DEVICE_FILE}" ]; then + echo "A TPM2 device with the in-kernel resource manager is needed!" >&2 + return 1 + fi + + if ! [[ -r "${TPM2TOOLS_DEVICE_FILE}" \ + && -w "${TPM2TOOLS_DEVICE_FILE}" ]]; then + echo "The ${TPM2TOOLS_DEVICE_FILE} device must be readable and writable!" >&2 + return 1 + fi + return 0 +} + +tpm2_version() { + local _tpm2tools_info + local _match='version="(.)\.' + _tpm2tools_info="$(tpm2_createprimary -v)" + [[ ${_tpm2tools_info} =~ ${_match} ]] && TPM2TOOLS_VERSION="${BASH_REMATCH[1]}" + if [[ $TPM2TOOLS_VERSION -lt 3 ]] || [[ $TPM2TOOLS_VERSION -gt 5 ]]; then + echo "The tpm2 pin requires a tpm2-tools version between 3 and 5" >&2 + return 1 + fi + export TPM2TOOLS_VERSION +} + +tpm2_sw_check_preconditions() { + [ -x "${SWTPM_BIN}" ] || skip_test "Skipping TPM1 test with software emulation, swtpm not found" + [ -x "${SWTPM_SETUP_BIN}" ] || skip_test "Skipping TPM1 test with software emulation, swtpm_setup not found" + [ -x "${SWTPM_BIOS_BIN}" ] || skip_test "Skipping TPM1 test with software emulation, swtpm_bios not found" + + if ! "${SWTPM_BIN}" socket --print-capabilities | jq -e '(.version | test("^0\\.[0-6](\\..*)?$")) or (.features | index("tpm-2.0"))' >/dev/null 2>&1; then + skip_test "Skipping TPM1 test with software emulation, no support for TPM 2.0 in swtpm" + fi +} + +tpm2_start_emulation() { + local socket_wait + echo "Starting TPM 2 emulation" >&2 + + # Setup TPM 2 data + "${SWTPM_SETUP_BIN}" --tpm-state "$TESTDIR" --tpm2 --create-ek-cert --create-platform-cert --lock-nvram --display >&2 || error "Unable to setup TPM 2 emulation" + + # Start emulation over socket + "${SWTPM_BIN}" socket --tpmstate dir="$TESTDIR" --tpm2 --ctrl type=unixio,path="$TESTDIR"/swtpm.sock.ctrl --server type=unixio,path="$TESTDIR"/swtpm.sock --flags not-need-init >&2 & + SWTPM_SOCKET_PID=$! + + socket_wait=1 + while [ $socket_wait -le 100 ]; do + [ -S "$TESTDIR"/swtpm.sock ] && break + socket_wait=$((socket_wait + 1)) + sleep 0.1 + done + [ "$socket_wait" -gt 100 ] && error "Unable to start TPM 1 emulation" + + # Run BIOS checks + "${SWTPM_BIOS_BIN}" --tpm2 --unix "$TESTDIR"/swtpm.sock || error "Unable to prepare TPM 1 emulation" + + export TPM2TOOLS_TCTI="swtpm:path=$TESTDIR/swtpm.sock" +}