| #!/usr/bin/env bash |
| #set -x |
| |
| # For the license, see the LICENSE file in the root directory. |
| |
| if [ "$(id -u)" -ne 0 ]; then |
| echo "Need to be root to run this test." |
| exit 77 |
| fi |
| |
| tmp="$(getenforce 2>&1)" |
| if [ "${tmp}" = "Enforcing" ]; then |
| echo "Test may not work with SELinux in enforcing mode." |
| exit 77 |
| fi |
| |
| # tpm2_ptool may not be packaged everywhere ... |
| if [ -z "$(type -P tpm2_ptool)" ]; then |
| echo "Could not find tpm2_ptool in PATH" |
| exit 77 |
| fi |
| |
| if ! tpm2_ptool | grep -q ",config,"; then |
| echo "tpm2_ptool does not support the config command" |
| exit 77 |
| fi |
| |
| if [ -z "$(type -P p11tool)" ]; then |
| echo "This test requires p11tool from gnutls-utils/gnutls-bin to be installed" |
| exit 77 |
| fi |
| |
| if [ -z "$(type -P tpm2-abrmd)" ]; then |
| echo "Could not find tpm2-abrmd in PATH" |
| exit 77 |
| fi |
| |
| if [ ! -r /usr/lib64/pkcs11/libtpm2_pkcs11.so ]; then |
| echo "/usr/lib64/pkcs11/libtpm2_pkcs11.so is missing" |
| echo "tpm2-pkcs11 package may not be installed." |
| exit 77 |
| fi |
| |
| ROOT=${abs_top_builddir:-$(dirname "$0")/..} |
| TESTDIR=${abs_top_testdir:=$(dirname "$0")} |
| SRCDIR=${abs_top_srcdir:-$(dirname "$0")/..} |
| |
| source "${TESTDIR}/common" |
| SWTPM_CREATE_TPMCA=${SRCDIR}/samples/swtpm-create-tpmca |
| |
| SWTPM_INTERFACE=socket+socket |
| SWTPM_SERVER_NAME=localhost |
| SWTPM_SERVER_PORT=65455 |
| SWTPM_CTRL_PORT=65454 |
| SWTPM_FAKE_CTRL_PORT=65456 |
| |
| workdir="$(mktemp -d)" || exit 1 |
| |
| SWTPM_LOCALCA_DIR="${workdir}/my localca" |
| SWTPM_LOCALCA_CONF="${workdir}/my localca/swtpm-localca.conf" |
| export TPM2_PKCS11_STORE="${workdir}" |
| TPM2_ABRMD_PIDFILE="${workdir}/tpm2-abrmd.pid" |
| |
| PID="" # primary object id returned by tpm2_ptool |
| TPM2_ABRMD_PID="" |
| |
| function cleanup() |
| { |
| if [ -n "${PID}" ]; then |
| echo "y" | tpm2_ptool destroy "${PID}" &>/dev/null |
| fi |
| if [ -n "${TPM2_ABRMD_PID}" ]; then |
| kill_quiet -9 "${TPM2_ABRMD_PID}" |
| fi |
| if [ -n "${SWTPM_PID}" ]; then |
| kill_quiet -9 "${SWTPM_PID}" |
| fi |
| if [ -n "${BASH_PID}" ]; then |
| kill_quiet -9 "${BASH_PID}" |
| fi |
| if [ -n "${NCAT_PID}" ]; then |
| kill_quiet -9 "${NCAT_PID}" |
| fi |
| rm -rf "${workdir}" |
| } |
| |
| trap "cleanup" SIGTERM EXIT |
| source "${TESTDIR}/common" |
| |
| PATH=${ROOT}/src/swtpm_bios:${ROOT}/src/swtpm_cert:${PATH} |
| |
| # Run the tests |
| # @param1: The vTPM for which the certificate is created is a TPM 2 |
| # @param2: The key algorithm for the created TPM 2 CA |
| function run_test() { |
| local algorithm="$1" |
| |
| local tmp certinfo regex regexs fil i exp_certsize alg |
| |
| rm -rf "${workdir:?}"/* |
| |
| cat <<_EOF_ > "${workdir}/swtpm_setup.conf" |
| create_certs_tool=${SWTPM_LOCALCA} |
| create_certs_tool_config=${workdir}/swtpm-localca.conf |
| create_certs_tool_options=/dev/null |
| _EOF_ |
| |
| if ! ${SWTPM_SETUP} \ |
| --tpm-state "${workdir}" \ |
| --logfile "${workdir}/logfile" \ |
| --config "${workdir}/swtpm_setup.conf" \ |
| --tpm "${SWTPM_EXE} socket ${SWTPM_TEST_SECCOMP_OPT}" \ |
| --swtpm_ioctl "${SWTPM_IOCTL}" \ |
| --tpm2 > /dev/null; then |
| echo "Error: Could not run $SWTPM_SETUP." |
| echo "Setup Logfile:" |
| cat "${workdir}/logfile" |
| exit 1 |
| fi |
| |
| SWTPM_SERVER_NO_DISCONNECT=1 run_swtpm "${SWTPM_INTERFACE}" \ |
| --tpm2 \ |
| --flags not-need-init \ |
| --tpmstate "dir=${workdir}" \ |
| --log level=0 |
| |
| ncat -l ${SWTPM_FAKE_CTRL_PORT} \ |
| -k -c "xargs --null -n1 printf '\x00\x00\x00\x00' 2>/dev/null" & |
| # shellcheck disable=SC2181 |
| if [ $? -ne 0 ]; then |
| echo "Could not start ncat" |
| exit 1 |
| fi |
| NCAT_PID=$! |
| if ! kill_quiet -0 ${NCAT_PID}; then |
| echo "ncat must have terminated" |
| exit 1 |
| fi |
| |
| bash -c "tpm2-abrmd --tcti=mssim:host=127.0.0.1,port=${SWTPM_SERVER_PORT} --allow-root & echo \$! > \"${TPM2_ABRMD_PIDFILE}\"; wait" & |
| BASH_PID=$! |
| |
| if wait_for_file "${TPM2_ABRMD_PIDFILE}" 3; then |
| echo "Error: Could not get tpm2-abrmd's PID file" |
| exit 1 |
| fi |
| |
| TPM2_ABRMD_PID=$(cat "${TPM2_ABRMD_PIDFILE}") |
| if ! kill_quiet -0 "${TPM2_ABRMD_PID}"; then |
| echo "Error: tpm2-abrmd with pid ${TPM2_ABRMD_PID} must have terminated" |
| exit 1 |
| fi |
| |
| if ! tmp="$(tpm2_ptool init 2>&1)"; then |
| echo "tpm2_ptool init failed:" |
| echo "${tmp}" |
| exit 1 |
| fi |
| PID="$(echo "${tmp}" | grep -E "^id:" |cut -d ":" -f2 | tr -d " ")" |
| if [ -z "${PID}" ]; then |
| echo "Could not grep the pid from the tpm2_ptool output" |
| echo "${tmp}" |
| exit 1 |
| fi |
| |
| if ! tmp="$(SWTPM_PKCS11_PIN="mypin 123" SWTPM_PKCS11_SO_PIN="123" ${SWTPM_CREATE_TPMCA} \ |
| --dir "${SWTPM_LOCALCA_DIR}" \ |
| --overwrite \ |
| --outfile "${SWTPM_LOCALCA_CONF}" \ |
| --group tss \ |
| --tpm2 \ |
| ${algorithm:+--algorithm "${algorithm}"} \ |
| --pid "${PID}" 2>&1)"; then |
| echo "Error: Could not create TPM CA" |
| echo "${tmp}" |
| exit 1 |
| fi |
| |
| for fil in \ |
| swtpm-localca-rootca-cert.pem \ |
| swtpm-localca-rootca-privkey.pem \ |
| swtpm-localca-tpmca-cert.pem \ |
| swtpm-localca-tpmca-pubkey.pem; do |
| if [ ! -r "${SWTPM_LOCALCA_DIR}/${fil}" ]; then |
| echo "Error: TPM CA tool did not create file ${fil}." |
| exit 1 |
| fi |
| done |
| |
| for regex in \ |
| "^statedir = " \ |
| "^signingkey = " \ |
| "^issuercert = " \ |
| "^certserial = " \ |
| "^SWTPM_PKCS11_PIN = mypin 123"; do |
| if [ -n "${regex}" ] && \ |
| ! grep -q -E "${regex}" "${SWTPM_LOCALCA_CONF}"; then |
| echo "Error: Could not find regex '${regex}' in CA config file." |
| cat "${SWTPM_LOCALCA_CONF}" |
| exit 1 |
| fi |
| done |
| |
| # make sure we can actually sign with this new certificate |
| if ! ${SWTPM_LOCALCA} \ |
| --type ek \ |
| --ek x=739192d8f1004283957a7b1568d610b41c637ccc114aadcac4908c20456468fa,y=59f63ac06f8011f6fdd1460c6bc8e3e0a2d090d4fc188c7e04870e06795ce8ae \ |
| --dir "${workdir}" --vmid test \ |
| --tpm2 \ |
| --tpm-spec-family 2.0 --tpm-spec-revision 146 --tpm-spec-level 00 \ |
| --tpm-model swtpm --tpm-version 20170101 --tpm-manufacturer IBM \ |
| --configfile "${SWTPM_LOCALCA_CONF}" \ |
| --optsfile /dev/null; then |
| echo "Error: The CA could not sign with the new certificate" |
| exit 1 |
| fi |
| if [ ! -f "${workdir}/ek.cert" ]; then |
| echo "Error: The CA did not produce a certificate" |
| exit 1 |
| fi |
| |
| case "${algorithm}" in |
| rsa2048) exp_certsize=500;; # cert should be ~541 bytes long; give some 'room' |
| ecc256) exp_certsize=460;; # cert should be ~476 bytes long; - " - |
| secp384r1) exp_certsize=510;; # cert should be ~519 bytes long; - " - |
| esac |
| |
| if [ "$(get_filesize "${workdir}/ek.cert")" -lt "${exp_certsize}" ]; then |
| echo "Error: The certificate's size is dubious" |
| ls -l "${workdir}/ek.cert" |
| exit 1 |
| fi |
| |
| # Check the contents of the certificate |
| certinfo=$(dd "if=${workdir}/ek.cert" bs=1 status=none | \ |
| openssl x509 -inform der -text -noout) |
| regexs=('^[[:space:]]+Endorsement Key Certificate$' |
| '^[[:space:]]+DirName:.*(/)tcg-at-tpmVersion=.*' |
| '^[[:space:]]+DirName:.*(/)?tcg-at-tpmManufacturer=IBM.*' |
| '^[[:space:]]+DirName:.*(/)?tcg-at-tpmModel=swtpm.*' |
| '^[[:space:]]+CA:FALSE$' |
| '^[[:space:]]+TPM Specification:$') |
| |
| case "${algorithm}" in |
| rsa2048) alg=sha256WithRSAEncryption;; |
| ecc256) alg=ecdsa-with-SHA256;; |
| secp384r1) alg=ecdsa-with-SHA384;; |
| esac |
| |
| # TPM 2.0; due to ecc: Key agreement |
| regexs+=('^[[:space:]]+Key Agreement$' |
| '^[[:space:]]+Signature Algorithm: '"${alg}"'$') |
| |
| for ((i=0; i < ${#regexs}; i++)); do \ |
| if [ -n "${regexs[$i]}" ] && \ |
| ! echo "${certinfo}" | grep -q -E "${regexs[$i]}"; then |
| echo "Error: Could not match regex '${regexs[$i]}' with certificate info:" |
| echo "${certinfo}" |
| exit 1 |
| fi |
| done |
| |
| # Send SIGTERM to tpm2-abrmd |
| kill_quiet -15 "${TPM2_ABRMD_PID}" |
| if wait_process_gone "${TPM2_ABRMD_PID}" 4; then |
| echo "Error: tpm2abrmd should not be running anymore." |
| exit 1 |
| fi |
| TPM2_ABRMD_PID="" |
| |
| if wait_process_gone "${BASH_PID}" 4; then |
| echo "Error: bash for tpm2abrmd should not be running anymore." |
| exit 1 |
| fi |
| BASH_PID="" |
| |
| kill_quiet -15 "${NCAT_PID}" |
| if wait_process_gone "${NCAT_PID}" 4; then |
| echo "Error: ncat should not be running anymore." |
| exit 1 |
| fi |
| NCAT_PID="" |
| |
| # Shut down TPM |
| if ! run_swtpm_ioctl "${SWTPM_INTERFACE}" -s; then |
| echo "Error: Could not shut down the ${SWTPM_INTERFACE} TPM." |
| exit 1 |
| fi |
| |
| if wait_process_gone "${SWTPM_PID}" 4; then |
| echo "Error: ${SWTPM_INTERFACE} TPM should not be running anymore." |
| exit 1 |
| fi |
| |
| SWTPM_PID="" |
| } # run_test |
| |
| run_test "rsa2048" |
| echo "Test 1: OK" |
| |
| run_test "ecc256" |
| echo "Test 2: OK" |
| |
| run_test "secp384r1" |
| echo "Test 3: OK" |
| |
| exit 0 |