summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@gnutls.org>2018-11-16 20:12:17 +0000
committerNikos Mavrogiannopoulos <nmav@gnutls.org>2018-11-16 20:12:17 +0000
commit03bed2a036d9c3f4e1e63b54f754fc54847dd5d4 (patch)
treede8beb48a2915b184b86fe9199e011f350ab9886
parent0f3dca28c5597a2813cad4ccc7770291230b3c95 (diff)
parent87dbcbe60176296e1e27da07b21aff52dc1c3038 (diff)
downloadgnutls-03bed2a036d9c3f4e1e63b54f754fc54847dd5d4.tar.gz
Merge branch 'tpm12_testing' into 'master'
tests: tpm: Add a test case for tpmtool See merge request gnutls/gnutls!807
-rw-r--r--.gitlab-ci.yml9
-rw-r--r--README.md5
-rw-r--r--lib/tpm.c1
-rw-r--r--src/tpmtool.c2
-rw-r--r--tests/Makefile.am4
-rw-r--r--tests/scripts/common.sh29
-rwxr-xr-xtests/tpmtool_test.sh427
7 files changed, 477 insertions, 0 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 7565a4204e..042059def5 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -109,6 +109,15 @@ minimal.Fedora.x86_64:
- shared
except:
- tags
+ artifacts:
+ expire_in: 1 week
+ when: on_failure
+ paths:
+ - ./*.log
+ - fuzz/*.log
+ - tests/*.log
+ - tests/*/*.log
+ - tests/suite/*/*.log
retry: 1
# This enables SSL3.0 and SHA-1 support, and runs interop tests
diff --git a/README.md b/README.md
index 89bc97205c..ac37e1d47b 100644
--- a/README.md
+++ b/README.md
@@ -45,6 +45,11 @@ We require several tools to check out and build the software, including:
* [bison](http://www.gnu.org/software/bison) (for datetime parser in certtool)
* [libunbound](https://unbound.net/) (for DANE support)
* [abi-compliance-checker](http://ispras.linuxbase.org/index.php/ABI_compliance_checker) (for make dist)
+* [tcsd](http://trousers.sourceforge.net/) (for TPM support; optional)
+* [swtpm](https://github.com/stefanberger/swtpm) (for TPM test; optional)
+* [ncat](https://nmap.org/download.html) (for TPM test; optional)
+* [tpm-tools](http://trousers.sourceforge.net/) (for TPM test; optional)
+* [expect](https://core.tcl.tk/expect/index) (for TPM test; optional)
The required software is typically distributed with your operating
system, and the instructions for installing them differ. Here are
diff --git a/lib/tpm.c b/lib/tpm.c
index 95bed111af..b97968838b 100644
--- a/lib/tpm.c
+++ b/lib/tpm.c
@@ -422,6 +422,7 @@ static int tpm_open_session(struct tpm_ctx_st *s, const char *_srk_password, uns
ret = tss_err(err);
goto out_srkpol;
}
+ gnutls_free(password);
return 0;
diff --git a/src/tpmtool.c b/src/tpmtool.c
index 3caa68ae3f..23085b1976 100644
--- a/src/tpmtool.c
+++ b/src/tpmtool.c
@@ -337,6 +337,7 @@ static void tpm_list(FILE * out)
else if (ret < 0) {
fprintf(stderr, "gnutls_tpm_key_list_get_url: %s\n",
gnutls_strerror(ret));
+ gnutls_tpm_key_list_deinit(list);
exit(1);
}
@@ -344,6 +345,7 @@ static void tpm_list(FILE * out)
gnutls_free(url);
}
+ gnutls_tpm_key_list_deinit(list);
fputs("\n", out);
}
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 826e6ef697..b8a7b66729 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -476,6 +476,10 @@ if ENABLE_DANE
dist_check_SCRIPTS += danetool.sh
endif
+if ENABLE_TROUSERS
+dist_check_SCRIPTS += tpmtool_test.sh
+endif
+
else
TESTS_ENVIRONMENT += WINDOWS=1
diff --git a/tests/scripts/common.sh b/tests/scripts/common.sh
index 10c25738dd..94333f19b3 100644
--- a/tests/scripts/common.sh
+++ b/tests/scripts/common.sh
@@ -212,3 +212,32 @@ create_testdir() {
trap "test -e \"$d\" && rm -rf \"$d\"" 1 15 2
echo "$d"
}
+
+wait_for_file() {
+ local filename="$1"
+ local timeout="$2"
+
+ local loops=$((timeout * 10)) loop=0
+
+ while test $loop -lt $loops; do
+ [ -f "$filename" ] && {
+ #allow file to be written to
+ sleep 0.2
+ return 1
+ }
+ sleep 0.1
+ loop=$((loop+1))
+ done
+ return 0
+}
+
+# Kill a process quietly
+# @1: signal, e.g. -9
+# @2: pid
+kill_quiet() {
+ local sig="$1"
+ local pid="$2"
+
+ sh -c "kill $sig $pid &>/dev/null"
+ return $?
+}
diff --git a/tests/tpmtool_test.sh b/tests/tpmtool_test.sh
new file mode 100755
index 0000000000..50ba23e3f2
--- /dev/null
+++ b/tests/tpmtool_test.sh
@@ -0,0 +1,427 @@
+#!/bin/sh
+
+# Copyright (C) 2018 IBM Corporation
+#
+# Author: Stefan Berger
+#
+# This file is part of GnuTLS.
+#
+# GnuTLS 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.
+#
+# GnuTLS 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 GnuTLS; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+srcdir="${srcdir:-.}"
+CERTTOOL="${CERTTOOL:-../src/certtool${EXEEXT}}"
+TPMTOOL="${TPMTOOL:-../src/tpmtool${EXEEXT}}"
+
+if [ "$(id -u)" -ne 0 ]; then
+ echo "Need to be root to run this test."
+ exit 77
+fi
+
+if [ -z "$(which swtpm 2>/dev/null)" ]; then
+ echo "Need swtpm package to run this test."
+ exit 77
+fi
+
+if [ -z "$(which tcsd 2>/dev/null)" ]; then
+ echo "Need tcsd (TrouSerS) package to run this test."
+ exit 77
+fi
+
+if [ -z "$(which tpm_createek 2>/dev/null)" ]; then
+ echo "Need tpm_createek from tpm-tools package to run this test."
+ exit 77
+fi
+
+if [ -z "$(which ncat 2>/dev/null)" ]; then
+ echo "Need ncat from nmap-ncat package to run this test."
+ exit 77
+fi
+
+if [ -z "$(which expect 2>/dev/null)" ]; then
+ echo "Need expect from expect package to run this test."
+ exit 77
+fi
+
+$TPMTOOL --help &>/dev/null
+if [ $? -ne 0 ]; then
+ echo "tpmtool cannot show help screen (TPMTOOL=$TPMTOOL)."
+ exit 77
+fi
+
+$CERTTOOL --help &>/dev/null
+if [ $? -ne 0 ]; then
+ echo "certtool cannot show help screen (CERTTOOL=$CERTTOOL)."
+ exit 77
+fi
+
+. "${srcdir}/scripts/common.sh"
+
+workdir=$(mktemp -d)
+
+SWTPM_SERVER_PORT=12345
+SWTPM_CTRL_PORT=$((SWTPM_SERVER_PORT + 1))
+SWTPM_PIDFILE=${workdir}/swtpm.pid
+TCSD_LISTEN_PORT=12347
+export TSS_TCSD_PORT=$TCSD_LISTEN_PORT
+
+cleanup()
+{
+ stop_tcsd
+ if [ -n "$workdir" ]; then
+ rm -rf $workdir
+ fi
+}
+
+start_swtpm()
+{
+ local workdir="$1"
+
+ local res
+
+ swtpm socket \
+ --flags not-need-init \
+ --pid file=$SWTPM_PIDFILE \
+ --tpmstate dir=$workdir \
+ --server type=tcp,port=$SWTPM_SERVER_PORT,disconnect \
+ --ctrl type=tcp,port=$SWTPM_CTRL_PORT &
+
+ if wait_for_file $SWTPM_PIDFILE 3; then
+ echo "Starting the swtpm failed"
+ return 1
+ fi
+
+ SWTPM_PID=$(cat $SWTPM_PIDFILE)
+ kill -0 ${SWTPM_PID}
+ if [ $? -ne 0 ]; then
+ echo "swtpm must have terminated"
+ return 1
+ fi
+
+ # Send TPM_Startup to TPM
+ res="$(/bin/echo -en '\x00\xC1\x00\x00\x00\x0C\x00\x00\x00\x99\x00\x01' |
+ ncat localhost ${SWTPM_SERVER_PORT} | od -tx1 -An)"
+ exp=' 00 c4 00 00 00 0a 00 00 00 00'
+ if [ "$res" != "$exp" ]; then
+ echo "Did not get expected response from TPM_Startup(ST_CLEAR)"
+ echo "expected: $exp"
+ echo "received: $res"
+ return 1
+ fi
+
+ return 0
+}
+
+stop_swtpm()
+{
+ if [ -n "$SWTPM_PID" ]; then
+ kill_quiet -15 $SWTPM_PID
+ unset SWTPM_PID
+ fi
+}
+
+start_tcsd()
+{
+ local workdir="$1"
+
+ local tcsd_conf=$workdir/tcsd.conf
+ local tcsd_system_ps_file=$workdir/system_ps_file
+ local tcsd_pidfile=$workdir/tcsd.pid
+
+ start_swtpm "$workdir"
+ [ $? -ne 0 ] && return 1
+
+ cat <<_EOF_ > $tcsd_conf
+port = $TCSD_LISTEN_PORT
+system_ps_file = $tcsd_system_ps_file
+_EOF_
+
+ chown tss:tss $tcsd_conf
+ chmod 0600 $tcsd_conf
+
+ bash -c "TCSD_USE_TCP_DEVICE=1 TCSD_TCP_DEVICE_PORT=$SWTPM_SERVER_PORT tcsd -c $tcsd_conf -e -f &>/dev/null & echo \$! > $tcsd_pidfile; wait" &
+ BASH_PID=$!
+
+ if wait_for_file $tcsd_pidfile 3; then
+ echo "Could not get TCSD's PID file"
+ return 1
+ fi
+
+ TCSD_PID=$(cat $tcsd_pidfile)
+ return 0
+}
+
+stop_tcsd()
+{
+ if [ -n "$TCSD_PID" ]; then
+ kill_quiet -15 $TCSD_PID
+ unset TCSD_PID
+ fi
+ stop_swtpm
+}
+
+run_tpm_takeownership()
+{
+ local owner_password="$1"
+ local srk_password="$2"
+
+ local prg out rc
+ local parm_z=""
+
+ if [ -z "$srk_password" ]; then
+ parm_z="--srk-well-known"
+ fi
+
+ prg="set parm_z \"$parm_z\"
+ spawn tpm_takeownership \$parm_z
+ expect {
+ \"Enter owner password:\"
+ { send \"$owner_password\n\" }
+ }
+ expect {
+ \"Confirm password:\"
+ { send \"$owner_password\n\" }
+ }
+ if { \$parm_z == \"\" } {
+ expect {
+ \"Enter SRK password:\"
+ { send \"$srk_password\n\" }
+ }
+ expect {
+ \"Confirm password:\"
+ { send \"$srk_password\n\" }
+ }
+ }
+ expect {
+ eof
+ }
+ catch wait result
+ exit [lindex \$result 3]
+ "
+ out=$(expect -c "$prg")
+ rc=$?
+ echo "$out"
+ return $rc
+}
+
+setup_tcsd()
+{
+ local workdir="$1"
+ local owner_password="$2"
+ local srk_password="$3"
+
+ local msg
+
+ start_tcsd "$workdir"
+ [ $? -ne 0 ] && return 1
+
+ tpm_createek
+ [ $? -ne 0 ] && {
+ echo "Could not create EK"
+ return 1
+ }
+ msg="$(run_tpm_takeownership "$owner_password" "$srk_password")"
+ [ $? -ne 0 ] && {
+ echo "Could not take ownership of TPM"
+ echo "$msg"
+ return 1
+ }
+ return 0
+}
+
+run_tpmtool()
+{
+ local srk_password="$1"
+ local key_password="$2"
+
+ shift 2
+
+ local prg out rc
+
+ prg="spawn $TPMTOOL $@
+ expect {
+ \"Enter SRK password:\" {
+ send \"$srk_password\n\"
+ exp_continue
+ }
+ \"Enter key password:\" {
+ send \"$key_password\n\"
+ exp_continue
+ }
+ \"tpmkey:\" {
+ exp_continue
+ }
+ eof
+ }
+ catch wait result
+ exit [lindex \$result 3]
+ "
+ out=$(expect -c "$prg")
+ rc=$?
+ echo "$out"
+ return $rc
+}
+
+tpmtool_test()
+{
+ local workdir="$1"
+ local owner_password="$2"
+ local srk_password="$3"
+ local key_password="$4"
+ local register=$5 # whether to --register the key
+
+ local params msg tpmkeyurl
+ local tpmpubkey=${workdir}/tpmpubkey.pem
+ local tpmca=${workdir}/tpmca.pem
+ local template=${workdir}/template
+ local tpmkey=${workdir}/tpmkey.pem # if --register is not used
+
+ setup_tcsd "$workdir" "$owner_password" "$srk_password"
+ [ $? -ne 0 ] && return 1
+
+ if [ -z "$srk_password" ]; then
+ params="--srk-well-known"
+ unset GNUTLS_PIN
+ else
+ export GNUTLS_PIN="$srk_password"
+ fi
+
+ if [ $register -ne 0 ]; then
+ # --register key
+ msg="$(run_tpmtool "$srk_password" "$key_password" \
+ $params --register --generate-rsa --signing)"
+ [ $? -ne 0 ] && {
+ echo "Could not create TPM signing key"
+ echo "$msg"
+ return 1
+ }
+ tpmkeyurl=$(echo "$msg" | sed -n 's/\(tpmkey:uuid=[^;]*\);.*/\1/p')
+ [ -z "$tpmkeyurl" ] && {
+ echo "Could not get TPM key URL"
+ return 1
+ }
+ else
+ msg="$(run_tpmtool "$srk_password" "$key_password" \
+ $params --generate-rsa --signing --outfile ${tpmkey})"
+ [ $? -ne 0 ] && {
+ echo "Could not create TPM signing key"
+ echo "$msg"
+ return 1
+ }
+ tpmkeyurl="tpmkey:file=${tpmkey}"
+ fi
+
+ if [ $register -ne 0 ]; then
+ msg=$(run_tpmtool "$srk_password" "$key_password" \
+ $params --test-sign $tpmkeyurl)
+ [ $? -ne 0 ] && {
+ echo "Could not test sign with key $tpmkeyurl"
+ echo "$msg"
+ return 1
+ }
+ fi
+
+ msg=$(run_tpmtool "$srk_password" "$key_password" \
+ $params --pubkey "$tpmkeyurl" --outfile "$tpmpubkey")
+ [ $? -ne 0 ] && {
+ echo "Could not get TPM key's public key"
+ echo "$msg"
+ return 1
+ }
+
+ cat <<_EOF_ >${template}
+cn = test
+ca
+cert_signing_key
+expiration_days = 1
+_EOF_
+
+ msg=$($CERTTOOL \
+ --generate-self-signed \
+ --template ${template} \
+ --outfile ${tpmca} \
+ --load-privkey ${tpmkeyurl} \
+ --load-pubkey ${tpmpubkey} 2>&1)
+ [ $? -ne 0 ] && {
+ echo "Could not create self-signed certificate"
+ echo "$msg"
+ return 1
+ }
+
+ echo "Successfully created TPM root CA cert using key $tpmkeyurl"
+
+ if [ $register -ne 0 ]; then
+ if [ -z "$($TPMTOOL --list | grep "${tpmkeyurl}")" ]; then
+ echo "TPM key '${tpmkeyurl}' was not found in list of TPM keys"
+ return 1
+ fi
+
+ msg=$(run_tpmtool "$srk_password" "$key_password" \
+ $params --delete $tpmkeyurl)
+ [ $? -ne 0 ] && {
+ echo "Could not delete TPM key ${tpmkeyurl}"
+ echo "$msg"
+ return 1
+ }
+
+ if [ -n "$($TPMTOOL --list | grep "$tpmkeyurl")" ]; then
+ echo "TPM key '$tpmkeyurl' was not properly deleted"
+ return 1
+ fi
+ fi
+
+ stop_tcsd
+}
+
+run_tests()
+{
+ local workdir="$1"
+
+ [ -z "$workdir" ] && {
+ echo "No workdir"
+ return 1
+ }
+ local srk_password key_password
+ local owner_password="owner"
+ local register
+
+ register=1
+ # Test with --register; key password is not needed
+ for srk_password in "" "s"; do
+ tpmtool_test "$workdir" "$owner_password" "$srk_password" "" "$register"
+ [ $? -ne 0 ] && return 1
+ stop_tcsd
+ rm ${workdir}/*
+ done
+
+ # Test without --register; the key needs a password, but it has to be the same as the
+ # srk_password due to a bug in TrouSerS
+ register=0
+ for srk_password in "s"; do
+ key_password=$srk_password
+ tpmtool_test "$workdir" "$owner_password" "$srk_password" "$key_password" "$register"
+ [ $? -ne 0 ] && return 1
+ stop_tcsd
+ rm ${workdir}/*
+ done
+
+ echo "Ok"
+
+ return 0
+}
+
+trap "cleanup" EXIT QUIT
+
+run_tests "$workdir"
+exit $?