samples: Extend script to create a CA using a TPM 2 for signing

Extend the script that creates a CA that uses a TPM 2 for signing.
For this we have to create tokens using the TPM 2 pkcs11 module's
tpm2_ptool and can then use the p11tool for creating keys.

Add a test case that requires a running tpm2-abrmd and tpm2_ptool.
Eventually the test case should (try to) start its own tpm2-abrmd
and talk to swtpm directly but the tcti module to do that isn't
available as a package, yet.

Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
This commit is contained in:
Stefan Berger 2018-10-29 22:02:06 -04:00 committed by Stefan Berger
parent eb9cfa963a
commit f30e202df6
5 changed files with 500 additions and 54 deletions

View File

@ -1,4 +1,4 @@
.\" Automatically generated by Pod::Man 4.11 (Pod::Simple 3.35)
.\" Automatically generated by Pod::Man 4.12 (Pod::Simple 3.39)
.\"
.\" Standard preamble:
.\" ========================================================================
@ -133,7 +133,7 @@
.\" ========================================================================
.\"
.IX Title "swtpm-create-tpmca 8"
.TH swtpm-create-tpmca 8 "2018-10-17" "swtpm" ""
.TH swtpm-create-tpmca 8 "2020-04-14" "swtpm" ""
.\" For nroff, turn off justification. Always turn off hyphenation; it makes
.\" way too many mistakes in technical documents.
.if n .ad l
@ -209,6 +209,19 @@ The hostname where tcsd is running on. The default hostname is 'localhost'.
.IX Item "-tss-tcsd-port"
The \s-1TCP\s0 port on which tcsd is listening for messages. The default port is
30003.
.IP "\fB\-\-tpm2\fR" 4
.IX Item "--tpm2"
The \s-1TPM\s0 to use for signing the certificates is a \s-1TPM 2\s0 and Intel's \s-1TSS\s0 stack
must be running (tpm2\-abrmd) along with its \s-1PKCS11\s0 module.
The \s-1TPM 2 PKCS11\s0 module must have been initialized using the tpm2_ptool.
.Sp
The environment variables \s-1SWTPM_PKCS11_PIN\s0 and \s-1SWTPM_PKCS11_SO_PIN\s0 should be
set to hold the PINs. If \s-1SWTPM_PKCS11_PIN\s0 is not set then the default \s-1PIN\s0
\&'swtpm\-tpmca' will be used. \s-1SWTPM_PKCS11_SO_PIN\s0 is needed for creating the
token and must be explicitly set as an environment variable.
.IP "\fB\-\-pid pimary-object-id\fR" 4
.IX Item "--pid pimary-object-id"
The primary object id that the tpm2_ptool returns upon 'init'.
.IP "\fB\-help, \-h, \-?\fR" 4
.IX Item "-help, -h, -?"
Display the help screen and exit.
@ -219,6 +232,9 @@ into /var/lib/swtpm\-localca and the swtpm-localca configuration to
/etc/swtpm\-localca.conf. It can then be used for signing certificates of
newly created \fBswtpm\fR TPMs.
.PP
If the host's \s-1TPM\s0 is a \s-1TPM 1.2,\s0 we need to start the tcsd first and can
then create the \s-1TPM\s0 key and \s-1TPM CA\s0 certificate:
.PP
.Vb 10
\& #> sudo systemctl start tcsd
\& #> sudo /usr/share/swtpm/swtpm\-create\-tpmca \e
@ -237,17 +253,57 @@ newly created \fBswtpm\fR TPMs.
\& signingkey_password = password
\& parentkey_password = password
.Ve
.PP
Alternatively, if the host's \s-1TPM\s0 is a \s-1TPM 2\s0 and Intel's \s-1TPM 2\s0 stack is
installed, we need to start tpm2\-abrmd first and can then create the \s-1TPM\s0 key
and \s-1TPM CA\s0 certificate:
.PP
.Vb 10
\& #> sudo systemctl start tpm2\-abrmd
\& #> tpm2_ptool init
\& action: Created
\& id: 1 # this is the \-\-pid parameter below
\& #> sudo SWTPM_PKCS11_PIN="mypin 123" SWTPM_PKCS11_SO_PIN=123 /usr/share/swtpm/swtpm\-create\-tpmca \e
\& \-\-dir /var/lib/swtpm\-localca \e
\& \-\-overwrite \e
\& \-\-outfile /etc/swtpm\-localca.conf \e
\& \-\-group tss \e
\& \-\-tpm2 \e
\& \-\-pid 1
\& statedir = /var/lib/swtpm\-localca
\& signingkey = pkcs11:model=SW%20%20%20TPM\e;manufacturer=IBM\e;serial=0000000000000000\e;token=swtpm\-tpmca\-1\e;id=%31\e;object=swtpm\-tpmca\-key\e;type=private
\& issuercert = /var/lib/swtpm\-localca/swtpm\-localca\-tpmca\-cert.pem
\& certserial = /var/lib/swtpm\-localca/certserial
\& SWTPM_PKCS11_PIN = mypin 123
.Ve
.PP
Note: This also works for non-root users by adapting the \-\-dir and \-\-outfile
parameters here and below by changing the \-\-dir parameter and adding a \-\-config
parameter.
.PP
To test either one of the above \s-1TPM\s0 CAs, run the following command:
.PP
.Vb 5
\& #> /usr/share/swtpm/swtpm\-localca \e
\& \-\-type ek \-\-ek x=11,y=13 \e
\& \-\-dir /tmp \-\-vmid test \-\-tpm2 \e
\& \-\-tpm\-spec\-family 2.0 \-\-tpm\-spec\-revision 146 \-\-tpm\-spec\-level 00 \e
\& \-\-tpm\-model swtpm \-\-tpm\-version 20170101 \-\-tpm\-manufacturer IBM
.Ve
.PP
The \-\-tpm2 in this command indicates that the \s-1TPM\s0 for which the certificate
is created is a \s-1TPM 2.\s0
.SH "KNOWN ISSUES"
.IX Header "KNOWN ISSUES"
The interaction of GnuTLS certtool with the \s-1TPM TCSD\s0 daemon may cause so
many \s-1TPM\s0 (key) authentication failures, that the \s-1TPM\s0 refuses to accept any
many \s-1TPM\s0 (key) authentication failures that the \s-1TPM\s0 refuses to accept any
more authenticated commands until the \s-1TPM\s0's owner sends it the
TPM_ORD_ResetLockValue command. The reason for this is that certtool first
tries to use 20 zero bytes for the \s-1SRK\s0 password and only then prompts for
and uses the required \s-1SRK\s0 password. The GnuTLS tpmtool does not support 20
zero bytes for the \s-1SRK\s0 password, so forces the usage of a 'real' password.
.PP
The effect of the authentication failues may be that the \s-1TPM CA\s0 cannot sign
The effect of the authentication failures may be that the \s-1TPM CA\s0 cannot sign
certificates since the \s-1TPM\s0 does not accept authenticated commands.
.SH "SEE ALSO"
.IX Header "SEE ALSO"

View File

@ -85,6 +85,21 @@ The hostname where tcsd is running on. The default hostname is 'localhost'.
The TCP port on which tcsd is listening for messages. The default port is
30003.
=item B<--tpm2>
The TPM to use for signing the certificates is a TPM 2 and Intel's TSS stack
must be running (tpm2-abrmd) along with its PKCS11 module.
The TPM 2 PKCS11 module must have been initialized using the tpm2_ptool.
The environment variables SWTPM_PKCS11_PIN and SWTPM_PKCS11_SO_PIN should be
set to hold the PINs. If SWTPM_PKCS11_PIN is not set then the default PIN
'swtpm-tpmca' will be used. SWTPM_PKCS11_SO_PIN is needed for creating the
token and must be explicitly set as an environment variable.
=item B<--pid pimary-object-id>
The primary object id that the tpm2_ptool returns upon 'init'.
=item B<-help, -h, -?>
Display the help screen and exit.
@ -98,6 +113,9 @@ into /var/lib/swtpm-localca and the swtpm-localca configuration to
/etc/swtpm-localca.conf. It can then be used for signing certificates of
newly created B<swtpm> TPMs.
If the host's TPM is a TPM 1.2, we need to start the tcsd first and can
then create the TPM key and TPM CA certificate:
#> sudo systemctl start tcsd
#> sudo /usr/share/swtpm/swtpm-create-tpmca \
--dir /var/lib/swtpm-localca \
@ -115,17 +133,54 @@ newly created B<swtpm> TPMs.
signingkey_password = password
parentkey_password = password
Alternatively, if the host's TPM is a TPM 2 and Intel's TPM 2 stack is
installed, we need to start tpm2-abrmd first and can then create the TPM key
and TPM CA certificate:
#> sudo systemctl start tpm2-abrmd
#> tpm2_ptool init
action: Created
id: 1 # this is the --pid parameter below
#> sudo SWTPM_PKCS11_PIN="mypin 123" SWTPM_PKCS11_SO_PIN=123 /usr/share/swtpm/swtpm-create-tpmca \
--dir /var/lib/swtpm-localca \
--overwrite \
--outfile /etc/swtpm-localca.conf \
--group tss \
--tpm2 \
--pid 1
statedir = /var/lib/swtpm-localca
signingkey = pkcs11:model=SW%20%20%20TPM\;manufacturer=IBM\;serial=0000000000000000\;token=swtpm-tpmca-1\;id=%31\;object=swtpm-tpmca-key\;type=private
issuercert = /var/lib/swtpm-localca/swtpm-localca-tpmca-cert.pem
certserial = /var/lib/swtpm-localca/certserial
SWTPM_PKCS11_PIN = mypin 123
Note: This also works for non-root users by adapting the --dir and --outfile
parameters here and below by changing the --dir parameter and adding a --config
parameter.
To test either one of the above TPM CAs, run the following command:
#> /usr/share/swtpm/swtpm-localca \
--type ek --ek x=11,y=13 \
--dir /tmp --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
The --tpm2 in this command indicates that the TPM for which the certificate
is created is a TPM 2.
=head1 KNOWN ISSUES
The interaction of GnuTLS certtool with the TPM TCSD daemon may cause so
many TPM (key) authentication failures, that the TPM refuses to accept any
many TPM (key) authentication failures that the TPM refuses to accept any
more authenticated commands until the TPM's owner sends it the
TPM_ORD_ResetLockValue command. The reason for this is that certtool first
tries to use 20 zero bytes for the SRK password and only then prompts for
and uses the required SRK password. The GnuTLS tpmtool does not support 20
zero bytes for the SRK password, so forces the usage of a 'real' password.
The effect of the authentication failues may be that the TPM CA cannot sign
The effect of the authentication failures may be that the TPM CA cannot sign
certificates since the TPM does not accept authenticated commands.
=head1 SEE ALSO

View File

@ -4,6 +4,7 @@ FLAG_OVERWRITE=1
FLAG_REGISTER_KEY=2
FLAG_TPMTOOL_SUPPORTS_SRK_WELL_KNOWN=4
FLAG_SRK_WELL_KNOWN=8
FLAG_TPM2=16
TSS_TCSD_HOSTNAME_DEFAULT=localhost
TSS_TCSD_PORT_DEFAULT=30003
@ -39,6 +40,14 @@ function get_filesize()
fi
}
# Create a config value by escaping the proper characters
#
# @param 1: The string to escape
function escape_pkcs11_url()
{
echo "$1" | sed 's/;/\\;/g'
}
# Use expect for automating the interaction with the tpmtool
#
# @param 1...: parameters to pass to tpmtool command line
@ -79,6 +88,7 @@ create_localca_cert() {
local dir="$2"
local outfile="$3"
local owner="$4"
local pid="$5" # TPM2 parameter
local cakey=${dir}/swtpm-localca-rootca-privkey.pem
local cacert=${dir}/swtpm-localca-rootca-cert.pem
@ -86,7 +96,7 @@ create_localca_cert() {
local tpmpubkey=${dir}/swtpm-localca-tpmca-pubkey.pem
local tpmca=${dir}/swtpm-localca-tpmca-cert.pem
local template=${dir}/template
local tpmkeyurl params
local tpmkeyurl
local msg output
if ! [ -r "${cakey}" ] || ! [ -r "${cacert}" ]; then
@ -126,52 +136,147 @@ create_localca_cert() {
rm -f "${tpmkey}" "${tpmpubkey}" "${tpmca}"
if [ $((flags & FLAG_SRK_WELL_KNOWN)) -ne 0 ]; then
unset GNUTLS_PIN
params="--srk-well-known"
else
export GNUTLS_PIN=${TPM_SRK_PASSWORD}
fi
if [ $((flags & FLAG_TPM2)) -ne 0 ]; then
local tokenurl tpmkeyurl
local token="swtpm-tpmca-${pid}"
local label="${token}" # must be same
local keylabel="swtpm-tpmca-key"
local userpin="${SWTPM_PKCS11_PIN:-swtpm-tpmca}"
if [ $((flags & FLAG_REGISTER_KEY)) -ne 0 ]; then
msg="$(run_tpmtool --generate-rsa --signing --register ${params})"
if [ $? -ne 0 ]; then
logerr "Could not generate registered signing key with tpmtool"
logerr "${msg}"
return 1
tokenurl=$(p11tool --list-tokens 2>&1 | \
grep -E ";token=${token}\$" | \
sed -n "s/.*URL: //p")
if [ -z "${tokenurl}" ]; then
if [ -z "${SWTPM_PKCS11_SO_PIN}" ]; then
logerr "The env. variable SWTPM_PKCS11_SO_PIN must be set to create token ${label}."
return 1
fi
msg=$(tpm2_ptool addtoken \
--pid "${pid}" \
--sopin "${SWTPM_PKCS11_SO_PIN}" \
--userpin "${userpin}" \
--label "${label}" 2>&1)
if [ $? -ne 0 ]; then
logerr "Error: Could not create pkcs11 token"
logerr "${msg}"
return 1
fi
tokenurl=$(p11tool --list-tokens 2>&1 | \
grep -E ";token=${token}\$" | \
sed -n "s/.*URL: //p")
if [ -z "${tokenurl}" ]; then
logerr "Error: Could not get token URL for token '${token}'"
logerr "${msg}"
return 1
fi
msg=$(tpm2_ptool config \
--key tcti \
--value tabrmd \
--label "${label}")
if [ $? -ne 0 ]; then
logerr "Error: Could not set config value for tcti key"
logerr "${msg}"
return 1
fi
fi
export GNUTLS_PIN="${userpin}"
# GNUTLS_SO_PIN not needed at this point
msg="$(p11tool --login --list-keys "${tokenurl}" 2>&1)"
if [ $? -eq 0 ]; then
tpmkeyurl=$(echo "${msg}" | \
grep ";object=${keylabel}" | \
sed -n "s/.*URL: //p")
fi
tpmkeyurl=$(echo "${msg}" | sed -n 's/\(tpmkey:uuid=[^;]*\);.*/\1/p')
if [ -z "${tpmkeyurl}" ]; then
logerr "Could not parse tpmkey URL"
msg=$(tpm2_ptool addkey \
"--label=${label}" \
"--userpin=${userpin}" \
--algorithm=rsa2048 \
"--key-label=${keylabel}" \
--id 1 2>&1)
if [ $? -ne 0 ]; then
logerr "Error: Could not create create key under pkcs11 token ${token}"
logerr "${msg}"
return 1
fi
msg="$(p11tool --login --list-keys "${tokenurl}" 2>&1)"
if [ $? -ne 0 ]; then
logerr "Error: Could not get TPM key URL for ${tokenurl}"
logerr "${msg}"
return 1
fi
tpmkeyurl=$(echo "${msg}" | \
grep ";object=${keylabel}" | \
sed -n "s/.*URL: //p")
if [ -z "${tpmkeyurl}" ]; then
logerr "Error: Could not get TPM key URL for ${tokenurl}"
logerr "${msg}"
return 1
fi
fi
rm -f "${tpmpubkey}"
msg=$(p11tool --export-pubkey "${tpmkeyurl}" --login --outfile "${tpmpubkey}" 2>&1)
if [ $? -ne 0 ] || \
[ ! -r "${tpmpubkey}" ] || [ $(get_filesize "${tpmpubkey}") -eq 0 ]; then
logerr "Error: Could not get TPM public key"
logerr "${msg}"
rm -f "${tpmkey}" "${tpmpubkey}"
return 1
fi
else
rm -f "${tpmkey}"
msg="$(run_tpmtool --generate-rsa --signing --outfile \"${tpmkey}\" ${params})"
if [ $? -ne 0 ]; then
logerr "Could not create signing key with tpmtool"
logerr "${msg}"
rm -f "${tpmkey}"
return 1
fi
if [ ! -r "${tpmkey}" ] || [ $(get_filesize "${tpmkey}") -eq 0 ]; then
logerr "The TPM key file ${tpmkey} was not written properly"
rm -f "${tpmkey}"
return 1
fi
chmod 640 "${tpmkey}"
tpmkeyurl="tpmkey:file=${tpmkey}"
fi
local params=""
rm -f "${tpmpubkey}"
msg=$(run_tpmtool "--pubkey=${tpmkeyurl}" --outfile \"${tpmpubkey}\" ${params})
if [ $? -ne 0 ] || \
[ ! -r "${tpmpubkey}" ] || [ $(get_filesize "${tpmpubkey}") -eq 0 ]; then
logerr "Error: Could not get TPM public key"
logerr "${msg}"
rm -f "${tpmkey}" "${tpmpubkey}"
return 1
if [ $((flags & FLAG_SRK_WELL_KNOWN)) -ne 0 ]; then
unset GNUTLS_PIN
params="--srk-well-known"
else
export GNUTLS_PIN="${TPM_SRK_PASSWORD}"
fi
if [ $((flags & FLAG_REGISTER_KEY)) -ne 0 ]; then
msg="$(run_tpmtool --generate-rsa --signing --register ${params})"
if [ $? -ne 0 ]; then
logerr "Could not generate registered signing key with tpmtool"
logerr "${msg}"
return 1
fi
tpmkeyurl=$(echo "${msg}" | sed -n 's/\(tpmkey:uuid=[^;]*\);.*/\1/p')
if [ -z "${tpmkeyurl}" ]; then
logerr "Could not parse tpmkey URL"
logerr "${msg}"
return 1
fi
else
rm -f "${tpmkey}"
msg="$(run_tpmtool --generate-rsa --signing --outfile \"${tpmkey}\" ${params})"
if [ $? -ne 0 ]; then
logerr "Could not create signing key with tpmtool"
logerr "${msg}"
rm -f "${tpmkey}"
return 1
fi
if [ ! -r "${tpmkey}" ] || [ $(get_filesize "${tpmkey}") -eq 0 ]; then
logerr "The TPM key file ${tpmkey} was not written properly"
logerr "${msg}"
rm -f "${tpmkey}"
return 1
fi
chmod 640 "${tpmkey}"
tpmkeyurl="tpmkey:file=${tpmkey}"
fi
rm -f "${tpmpubkey}"
msg=$(run_tpmtool "--pubkey=${tpmkeyurl}" --outfile \"${tpmpubkey}\" ${params})
if [ $? -ne 0 ] || \
[ ! -r "${tpmpubkey}" ] || [ $(get_filesize "${tpmpubkey}") -eq 0 ]; then
logerr "Error: Could not get TPM public key"
logerr "${msg}"
rm -f "${tpmkey}" "${tpmpubkey}"
return 1
fi
fi
echo "cn=swtpm-localca" > "${template}"
@ -197,12 +302,17 @@ create_localca_cert() {
fi
output="statedir = ${dir}
signingkey = ${tpmkeyurl}
signingkey = $(escape_pkcs11_url ${tpmkeyurl})
issuercert = ${tpmca}
certserial = ${dir}/certserial
TSS_TCSD_HOSTNAME = ${TSS_TCSD_HOSTNAME}
TSS_TCSD_PORT = ${TSS_TCSD_PORT}"
certserial = ${dir}/certserial"
if [ $((flags & FLAG_TPM2)) -eq 0 ]; then
output+="$(echo -e "\nTSS_TCSD_HOSTNAME = ${TSS_TCSD_HOSTNAME}")"
output+="$(echo -e "\nTSS_TCSD_PORT = ${TSS_TCSD_PORT}")"
else
output+="$(echo -e "\nSWTPM_PKCS11_PIN = ${SWTPM_PKCS11_PIN}")"
# output+="$(echo -e "\nSWTPM_PKCS11_SO_PIN = ${SWTPM_PKCS11_SO_PIN}")"
fi
if [ -n "${TPM_KEY_PASSWORD}" ]; then
output+="$(echo -e "\nsigningkey_password = ${TPM_KEY_PASSWORD}")"
fi
@ -259,7 +369,8 @@ The following options are supported:
--overwrite Overwrite any data in an existing directory; tries to
reuse a root CA if one is found there
--register Create a registered TPM 1.2 key rather than a file that
contains the key
contains the key; this option has no effect if --tpm2 is
used
--key-password s Password for the newly created TPM key; required if
--register is not passed
Note: use the same as the --srk-password (bug in certtool)
@ -275,6 +386,9 @@ The following options are supported:
on; default is '${TSS_TCSD_HOSTNAME_DEFAULT}'
--tss-tcsd-port p The TCP port on which tcsd is listening for connections;
default is ${TSS_TCSD_PORT_DEFAULT}
--tpm2 Setup a CA that uses a TPM 2.0
--pid <pid> Pimary object Id used by tpm2_ptool; only valid if --tpm2
is used
--help, -h, -? Display this help screen and exit
@ -297,7 +411,7 @@ tpmtool_supports_srk_well_known()
main() {
local flags=0
local dir outfile owner group msg
local dir outfile owner group msg pid
if tpmtool_supports_srk_well_known; then
flags=$((flags | FLAG_TPMTOOL_SUPPORTS_SRK_WELL_KNOWN | FLAG_SRK_WELL_KNOWN))
@ -348,6 +462,13 @@ main() {
shift
TSS_TCSD_PORT="$1"
;;
--tpm2)
flags=$((flags | FLAG_TPM2))
;;
--pid)
shift
pid="$1"
;;
--help|-h|-?)
usage "$0" "${flags}"
exit 0
@ -371,17 +492,24 @@ main() {
return 1
fi
if [ -z "${TPM_SRK_PASSWORD}" ] && \
if [ -z "${TPM_SRK_PASSWORD}" ] && [ $((flags & FLAG_TPM2)) -eq 0 ] &&
[ $((flags & FLAG_TPMTOOL_SUPPORTS_SRK_WELL_KNOWN)) -eq 0 ]; then
logerr "SRK password must be provided"
return 1
fi
if [ -z "${TPM_KEY_PASSWORD}" ] && [ $((flags & FLAG_REGISTER_KEY)) -eq 0 ]; then
if [ -z "${TPM_KEY_PASSWORD}" ] && \
[ $((flags & FLAG_REGISTER_KEY)) -eq 0 ] && \
[ $((flags & FLAG_TPM2)) -eq 0 ]; then
logerr "Key password is required"
return 1
fi
if [ $((flags & FLAG_TPM2)) -ne 0 ] && [ -z "${pid}" ]; then
logerr "--pid is required for TPM 2"
return 1
fi
if [ "$(id -u)" -eq 0 ]; then
if [ -n "${owner}" ]; then
msg="$(id -u "${owner}" 2>&1)"
@ -409,7 +537,7 @@ main() {
return 1
fi
create_localca_cert "${flags}" "${dir}" "${outfile}" "${owner}"
create_localca_cert "${flags}" "${dir}" "${outfile}" "${owner}" "${pid}"
return $?
} #main

View File

@ -78,6 +78,7 @@ if WITH_GNUTLS
TESTS += \
test_swtpm_cert \
test_tpm2_parameters \
test_tpm2_samples_create_tpmca \
test_tpm2_samples_swtpm_localca \
test_tpm2_samples_swtpm_localca_pkcs11 \
test_tpm2_swtpm_cert \

View File

@ -0,0 +1,206 @@
#!/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
# tpm2_ptool may not be packaged everywhere ...
if [ -z "$(type -P tpm2_ptool)" ]; then
echo "Could not find tpmtool in PATH"
exit 77
fi
if [ -z "$(tpm2_ptool | grep ",config,")" ]; then
echo "tpm2_ptool does not support the config command"
exit 77
fi
msg=$(systemctl status tpm2-abrmd 2>&1)
if [ $? -ne 0 ]; then
echo "tpm2-abrmd must be running"
exit 77
fi
ROOT=${abs_top_builddir:-$(dirname "$0")/..}
TESTDIR=${abs_top_testdir:=$(dirname "$0")}
SRCDIR=${abs_top_srcdir:-$(dirname "$0")/..}
SWTPM_SETUP=${ROOT}/src/swtpm_setup/swtpm_setup
SWTPM_CREATE_TPMCA=${SRCDIR}/samples/swtpm-create-tpmca
SWTPM_LOCALCA=${SRCDIR}/samples/swtpm-localca
SWTPM=${ROOT}/src/swtpm/swtpm
SWTPM_IOCTL=${ROOT}/src/swtpm_ioctl/swtpm_ioctl
SWTPM_INTERFACE=socket+socket
SWTPM_SERVER_NAME=localhost
SWTPM_SERVER_PORT=65434
SWTPM_CTRL_PORT=65435
workdir=$(mktemp -d)
SWTPM_LOCALCA_DIR="${workdir}/my localca"
SWTPM_LOCALCA_CONF="${workdir}/my localca/swtpm-localca.conf"
PID="" # primary object id returned by tpm2_ptool
function cleanup()
{
if [ -n "${PID}" ]; then
echo "y" | tpm2_ptool destroy ${PID} &>/dev/null
fi
rm -rf "${workdir}"
}
trap "cleanup" SIGTERM EXIT
source ${TESTDIR}/common
case "$(uname -s)" in
Darwin)
CERTTOOL=gnutls-certtool;;
*)
CERTTOOL=certtool;;
esac
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
function run_test() {
local vtpm_is_tpm2="$1"
local tmp params certinfo regex regexs fil i skip
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_
tmp="$(tpm2_ptool init 2>&1)"
if [ $? -ne 0 ]; 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
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 \
--pid "${PID}")"
if [ $? -ne 0 ]; 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}" ] && \
[ -z "$(grep -E "${regex}" "${SWTPM_LOCALCA_CONF}")" ]; then
echo "Error: Could not find regex '${line}' in CA config file."
cat "${SWTPM_LOCALCA_CONF}"
exit 1
fi
done
params=""
if [ ${vtpm_is_tpm2} -ne 0 ]; then
params="--tpm2"
skip=0
else
skip=7 # header in cert
fi
# make sure we can actually sign with this new certificate
${SWTPM_LOCALCA} \
--type ek \
--ek x=739192d8f1004283957a7b1568d610b41c637ccc114aadcac4908c20456468fa,y=59f63ac06f8011f6fdd1460c6bc8e3e0a2d090d4fc188c7e04870e06795ce8ae \
--dir "${workdir}" --vmid test \
${params} \
--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
if [ $? -ne 0 ]; 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
# cert was for example 541 bytes long
if [ $(get_filesize "${workdir}/ek.cert") -lt 500 ]; 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 "skip=$skip" status=none | \
"$CERTTOOL" -i --inder)
regexs=('^[[:space:]]+2.23.133.8.1$'
'^[[:space:]]+directoryName:.*(,)?2.23.133.2.3=.*'
'^[[:space:]]+directoryName:.*(,)?2.23.133.2.2=.*'
'^[[:space:]]+directoryName:.*(,)?2.23.133.2.1=.*'
'^[[:space:]]+Certificate Authority \(CA\): FALSE$'
'^[[:space:]]+Unknown extension 2.5.29.9 \(not critical\):$'
'^[[:space:]]+Hexdump: 3019301706056781050210310e300c0c03322e3002010002020092$')
if [ ${vtpm_is_tpm2} -ne 0 ]; then
# TPM 2.0; due to ecc: Key agreement
regexs+=('^[[:space:]]+Key agreement\.$'
'^[[:space:]]+Signature Algorithm: RSA-SHA256$')
else
regexs+=('^[[:space:]]+Key encipherment\.$'
'^[[:space:]]+Signature Algorithm: RSA-SHA1$')
fi
for ((i=0; i < ${#regexs}; i++)); do \
if [ -n "${regexs[$i]}" ] && \
[ -z "$(echo "${certinfo}" | grep -E "${regexs[$i]}")" ]; then
echo "Error: Could not match regex '${regexs[$i]}' with certificate info:"
echo "${certinfo}"
exit 1
fi
done
} # run_test
run_test 1
echo "Test 1: OK"
run_test 0
echo "Test 2: OK"
exit 0