swtpm_setup: Implement support for ECC keys

Implement support in swtpm_setup.sh so that the TPM's primary key
can be an ECC key.

Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
This commit is contained in:
Stefan Berger 2016-12-21 17:06:40 -05:00
parent 276eee02b4
commit 08da93a96f
6 changed files with 192 additions and 6 deletions

View File

@ -46,6 +46,9 @@ ek.cert and the platform certificate under the name platform.cert.
This parameter indicates the modulus of the public key of the endorsement key
(EK). The public key is provided as a sequence of ASCII hex digits.
In case ECC (elliptic curve crypography) keys are used, the parameter must
have the format --ek x=<hex digits>,y=<hex digits>.
=item B<--vmid ID>
This parameter indicates the ID of the VM for which to create the certificate.

View File

@ -49,6 +49,10 @@ Create the EK
Create an EK that can sign. This option requires --tpm2.
=item B<--ecc>
Create elliptic curve crypto (ECC) keys; by default RSA keys are generated.
=item B<--take-ownership>
Take ownership; this option implies --createek

View File

@ -138,7 +138,7 @@ create_cert() {
local tpm_attr_params="$7"
local serial=$(get_next_cert_serial)
local options="" rc=0
local options="" rc=0 keyparms=""
if [ -z "$serial" ]; then
return 1
@ -161,6 +161,16 @@ create_cert() {
options="$options --add-header"
fi
# if ek contains x=..,y=... it's an ECC key
if [[ "$ek" =~ x=.*,y=.* ]]; then
keyparms="--ecc-x \"$(echo $ek | \
sed -n 's/x=\([[:xdigit:]]\+\),.*/\1/p')\" "
keyparms+="--ecc-y \"$(echo $ek | \
sed -n 's/.*y=\([[:xdigit:]]\+\)/\1/p')\""
else
keyparms="--modulus \"${ek}\""
fi
case "$typ" in
ek)
if [ -z "$(type -p swtpm_cert)" ]; then
@ -174,7 +184,7 @@ create_cert() {
--signkey ${SIGNKEY} \
--issuercert ${ISSUERCERT} \
--out-cert ${dir}/ek.cert \
--modulus "${ek}" \
$keyparms \
--days $((10*365)) \
--serial $serial
if [ $? -eq 0 ]; then
@ -197,7 +207,7 @@ create_cert() {
--signkey ${SIGNKEY} \
--issuercert ${ISSUERCERT} \
--out-cert ${dir}/platform.cert \
--modulus "${ek}" \
$keyparms \
--days $((10*365)) \
--serial $serial
if [ $? -eq 0 ]; then

View File

@ -78,6 +78,7 @@ SETUP_STATE_OVERWRITE_F=128
SETUP_STATE_NOT_OVERWRITE_F=256
SETUP_TPM2_F=512
SETUP_ALLOW_SIGNING_F=1024
SETUP_TPM2_ECC_F=2048
SETUP_DISPLAY_RESULTS_F=4096
@ -119,6 +120,9 @@ NB256=${NB32}${NB32}${NB32}${NB32}${NB32}${NB32}${NB32}${NB32}
NONCE_RSA='\x01\x00'${NB256}
NONCE_RSA_SIZE=256
NONCE_ECC='\x00\x20'${NB32}
NONCE_ECC_SIZE=32
trap "cleanup" SIGTERM EXIT
logit()
@ -898,6 +902,112 @@ tpm2_createprimary_rsa()
return 0
}
# Create the primary key as an ECC key (EK equivalent)
#
# @param1: flags
tpm2_createprimary_ecc()
{
local flags="$1"
local req rsq exp res min_exp
local flags="$1"
local req rsq exp res symkeydata keyflags totlen publen off1 off2
if [ $((flags & SETUP_ALLOW_SIGNING_F)) -ne 0 ]; then
# keyflags: fixedTPM, fixedParent, sensitiveDatOrigin,
# adminWithPolicy, sign, decrypt
keyflags=$((0x000600b2))
# symmetric: TPM_ALG_NULL
symkeydata='\\x00\\x10'
publen=$((0x36 + 2 * NONCE_ECC_SIZE))
totlen=$((0x5f + 2 * NONCE_ECC_SIZE))
min_exp=930
# offset of length indicator for key
off1=210
off2=312
else
# keyflags: fixedTPM, fixedParent, sensitiveDatOrigin,
# adminWithPolicy, restricted, decrypt
keyflags=$((0x000300b2))
# symmetric: TPM_ALG_AES, 128bit, TPM_ALG_CFB
symkeydata='\\x00\\x06\\x00\\x80\\x00\\x43'
publen=$((0x3a + 2 * NONCE_ECC_SIZE))
totlen=$((0x63 + 2 * NONCE_ECC_SIZE))
# some version of TPM2 returns 942, another 990
min_exp=942
# offset of length indicator for key
off1=222
off2=324
fi
# Check the TCG EK Credential Profile doc for TPM 2 for
# parameters used here
req='\x80\x02@TOTLEN-4@\x00\x00\x01\x31'
# TPM_RH_ENDORSEMENT
req+='\x40\x00\x00\x0b'
# size of buffer
req+='\x00\x00\x00\x09'
# TPM_RS_PW
req+='\x40\x00\x00\x09\x00\x00\x00\x00\x00'
# TPM2B_SENSITIVE_CREATE
req+='\x00\x04\x00\x00\x00\x00'
# Size of TPM2B_PUBLIC
req+='@PUBLEN-2@'
# TPM_ALG_ECC, TPM_ALG_SHA256
req+='\x00\x23\x00\x0b'
# flags: fixedTPM, fixedParent, sensitiveDatOrigin, adminWithPolicy
# restricted, decrypt
req+='@KEYFLAGS-4@'
# authPolicy: size = 32 bytes
req+='\x00\x20'
req+='\x83\x71\x97\x67\x44\x84\xb3\xf8\x1a\x90\xcc\x8d'
req+='\x46\xa5\xd7\x24\xfd\x52\xd7\x6e\x06\x52\x0b\x64'
req+='\xf2\xa1\xda\x1b\x33\x14\x69\xaa'
req+='@SYMKEYDATA@'
# scheme: TPM_ALG_NULL, curveID: TPM_ECC_NIST_P256
req+='\x00\x10\x00\x03'
# kdf->scheme: TPM_ALG_NULL
req+='\x00\x10'
# TPM2B_DATA for x and y
req+=${NONCE_ECC}
req+=${NONCE_ECC}
# TPML_PCR_SELECTION
req+='\x00\x00\x00\x00\x00\x00'
req=$(echo $req | \
sed -e "s/@KEYFLAGS-4@/$(_format "$keyflags" 4)/" \
-e "s/@SYMKEYDATA@/$symkeydata/" \
-e "s/@PUBLEN-2@/$(_format "$publen" 2)/" \
-e "s/@TOTLEN-4@/$(_format "$totlen" 4)/")
rsp="$(tpm_transfer "${req}")"
if [ ${#rsp} -lt $min_exp ]; then
logerr "TPM2_CreatePrimary(ECC) failed"
logerr " expected at least $min_exp bytes, got ${#rsp}."
logerr " response: $rsp"
return 1
fi
# Check the x and y length indicators
if [ "${rsp:$off1:6}" != " 00 20" ] || \
[ "${rsp:$off2:6}" != " 00 20" ]; then
logerr "Getting ECC x and y parameter from wrong offset."
return 1
fi
let off1=off1+6
let off2=off2+6
# output: handle,ek
res="$(echo "0x${rsp:30:12}" | sed -n 's/ //pg'),"
res+="$(echo x=${rsp:$off1:96},y=${rsp:$off2:96} | sed -n 's/ //pg')"
echo $res
return 0
}
# Make a object permanent
#
# @param1: the current object handle
@ -944,7 +1054,11 @@ tpm2_createprimary()
tpm2_changeeps
[ $? -ne 0 ] && return 1
res=$(tpm2_createprimary_rsa "$flags")
if [ $((flags & SETUP_TPM2_ECC_F)) -ne 0 ]; then
res=$(tpm2_createprimary_ecc "$flags")
else
res=$(tpm2_createprimary_rsa "$flags")
fi
[ $? -ne 0 ] && return 1
handle=$(echo $res | cut -d "," -f1)
@ -954,7 +1068,7 @@ tpm2_createprimary()
[ $? -ne 0 ] && return 1
# ek
echo $res | cut -d "," -f2
echo $res | cut -d "," -f2-
return 0
}
@ -1326,6 +1440,8 @@ The following options are supported:
--allow-signing : Create an EK that can also be used for signing;
this option requires --tpm2.
--ecc : Create ECC keys rather than RSA keys; this requires --tpm2
--take-ownership : Take ownership; this option implies --createek
--ownerpass <password>
: Provide custom owner password; default is $DEFAULT_OWNER_PASSWORD
@ -1393,6 +1509,7 @@ main()
--tpm) shift; SWTPM="$1";;
--swtpm_ioctl) shift; SWTPM_IOCTL="$1";;
--tpm2) flags=$((flags | SETUP_TPM2_F));;
--ecc) flags=$((flags | SETUP_TPM2_ECC_F));;
--createek) flags=$((flags | SETUP_CREATE_EK_F));;
--take-ownership) flags=$((flags |
SETUP_CREATE_EK_F|SETUP_TAKEOWN_F));;
@ -1472,6 +1589,11 @@ main()
logerr "Taking ownership is not supported for TPM 2."
exit 1
fi
else
if [ $((flags & SETUP_TPM2_ECC_F)) -ne 0 ]; then
logerr "--ecc requires --tpm2."
exit 1
fi
fi
check_state_overwrite "$flags" "$tpm_state_path"

View File

@ -15,6 +15,14 @@ PARAMETERS=(
"--createek --allow-signing --create-ek-cert --create-platform-cert --config ${DIR}/swtpm_setup.conf --vmid test --display"
"--createek --allow-signing --create-ek-cert --create-platform-cert --config ${DIR}/swtpm_setup.conf --vmid test --display --keyfile ${DIR}/data/keyfile.txt"
"--createek --allow-signing --create-ek-cert --create-platform-cert --config ${DIR}/swtpm_setup.conf --vmid test --display --pwdfile ${DIR}/data/pwdfile.txt"
"--ecc --createek"
"--ecc --createek --create-ek-cert --create-platform-cert --config ${DIR}/swtpm_setup.conf --vmid test --display"
"--ecc --createek --create-ek-cert --create-platform-cert --config ${DIR}/swtpm_setup.conf --vmid test --display --keyfile ${DIR}/data/keyfile.txt"
"--ecc --createek --create-ek-cert --create-platform-cert --config ${DIR}/swtpm_setup.conf --vmid test --display --pwdfile ${DIR}/data/pwdfile.txt"
"--ecc --createek --allow-signing"
"--ecc --createek --allow-signing --create-ek-cert --create-platform-cert --config ${DIR}/swtpm_setup.conf --vmid test --display"
"--ecc --createek --allow-signing --create-ek-cert --create-platform-cert --config ${DIR}/swtpm_setup.conf --vmid test --display --keyfile ${DIR}/data/keyfile.txt"
"--ecc --createek --allow-signing --create-ek-cert --create-platform-cert --config ${DIR}/swtpm_setup.conf --vmid test --display --pwdfile ${DIR}/data/pwdfile.txt"
)
# produced file size is always the same with TPM2

View File

@ -93,6 +93,45 @@ if [ ! -r "${CERTSERIAL}" ]; then
exit 1
fi
echo "OK"
echo "Test 1: OK"
rm -rf ${SIGNINGKEY} ${ISSUERCERT} ${CERTSERIAL}
# we need to create at least one cert: --create-ek-cert
$SWTPM_SETUP \
--tpm2 \
--ecc \
--runas root \
--tpm-state ${workdir} \
--create-ek-cert \
--config ${workdir}/swtpm_setup.conf \
--logfile ${workdir}/logfile \
--tpm "${SWTPM} socket" \
--swtpm_ioctl ${SWTPM_IOCTL} \
--overwrite
if [ $? -ne 0 ]; then
echo "Error: Could not run $SWTPM_SETUP."
echo "Logfile output:"
cat ${workdir}/logfile
exit 1
fi
if [ ! -r "${SIGNINGKEY}" ]; then
echo "Error: Signingkey file ${SIGNINGKEY} was not created."
exit 1
fi
if [ ! -r "${ISSUERCERT}" ]; then
echo "Error: Issuer cert file ${ISSUERCERT} was not created."
exit 1
fi
if [ ! -r "${CERTSERIAL}" ]; then
echo "Error: Cert serial number file ${CERTSERIAL} was not created."
exit 1
fi
echo "Test 2: OK"
exit 0