Skip to content

Commit

Permalink
tests: Add script to generate IAK and IDevID certificates
Browse files Browse the repository at this point in the history
The script generates a test root CA and intermediate CA keys and
certificates. The output directory can be set via the --output option,
and the CA password with the --pwd option.  If an output directory is
not set, a temporary directory is created and the certificates are
placed there.

Then, the script generates the IDevID and IAK keys inside the TPM and
respective certificates.

The script requires the tpm2-openssl provider to access the keys inside
the TPM.

It is recommended to set the TCTI, TPM2TOOLS_TCTI, and TPM2OPENSSL_TCTI
environment variables to set which TPM to use when running the script.
If these variables are not set, the default value `device:/dev/tpmrm0`
is used instead.

This also modifies the tests/setup_swtpm.sh and tests/run.sh to
configure the TPM2OPENSSL_TCTI to use the swtpm with the tpm2-openssl
provider.

Signed-off-by: Anderson Toshiyuki Sasaki <[email protected]>
  • Loading branch information
ansasaki committed Dec 5, 2024
1 parent d7926da commit 82c1f6c
Show file tree
Hide file tree
Showing 4 changed files with 392 additions and 0 deletions.
111 changes: 111 additions & 0 deletions tests/ca.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
[ ca ]
default_ca = CA_default

[ CA_default ]
dir = REPLACE_ROOT_CA_DIR
certs = $dir/certs
crl_dir = $dir/crl
new_certs_dir = $dir/certs
database = $dir/index.txt
serial = $dir/serial
RANDFILE = $dir/.rand

private_key = $dir/private.pem
certificate = $dir/cacert.pem

crlnumber = $dir/crl/crlnumber
crl = $dir/crl/ca.crl.pem
crl_extensions = crl_ext
default_crl_days = 30

default_md = sha256

name_opt = ca_default
cert_opt = ca_default
default_days = 375
preserve = no
policy = policy_strict

[ CA_intermediate ]
dir = REPLACE_INTERMEDIATE_CA_DIR
certs = $dir/certs
crl_dir = $dir/crl
new_certs_dir = $dir/certs
database = $dir/index.txt
serial = $dir/serial
RANDFILE = $dir/.rand

private_key = $dir/private.pem
certificate = $dir/cacert.pem

crlnumber = $dir/crl/crlnumber
crl = $dir/crl/intermediate.crl.pem
crl_extensions = crl_ext
default_crl_days = 30

default_md = sha256

name_opt = ca_default
cert_opt = ca_default
default_days = 375
preserve = no
policy = policy_loose
unique_subject = no

[ policy_strict ]
countryName = match
stateOrProvinceName = match
organizationName = match
organizationalUnitName = optional
commonName = optional
emailAddress = optional

[ policy_loose ]
countryName = match
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = optional
emailAddress = optional

[ req ]
prompt = no
default_bits = 2048
distinguished_name = req_distinguished_name
string_mask = utf8only

default_md = sha256

x509_extensions = v3_ca

[ req_distinguished_name ]
C = US
ST = MA
L = Lexington
O = Keylime Tests

[ v3_ca ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true
keyUsage = critical, digitalSignature, cRLSign, keyCertSign

[ v3_intermediate_ca ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true, pathlen:0
keyUsage = critical, digitalSignature, cRLSign, keyCertSign

[ server_cert ]
# Extensions for server certificates (`man x509v3_config`).
basicConstraints = CA:FALSE
nsCertType = server
nsComment = "OpenSSL Generated Server Certificate"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer:always
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
# These OIDs are taken from the SubjectAltName from section 8.1 of the TPM 2.0 Keys for Device Identity and Attestation
# https://trustedcomputinggroup.org/wp-content/uploads/TPM-2p0-Keys-for-Device-Identity-and-Attestation_v1_r12_pub10082021.pdf
subjectAltName=DER:306FA06D06082B06010505070804A061305F0605678105010204565354000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
275 changes: 275 additions & 0 deletions tests/generate-iak-idevid-certs.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,275 @@
#!/bin/bash

# Generate a test root CA and intermediate CA keys and certificates
# Then, generate IAK and IDevID keys inside the TPM and certificates signed by
# the interemediate CA

GIT_ROOT=$(git rev-parse --show-toplevel)
if [[ $? -ne 0 ]]; then
echo "Please run this script from inside the rust-keylime repository tree"
fi

TESTS_DIR=${GIT_ROOT}/tests
GIT_CA_CONF=${TESTS_DIR}/ca.conf
CA_PWD=keylime

# It is expected that the TCTI and TPM2TOOLS_TCTI environment variables are set
# before running the script

if [[ -z "$TCTI" ]]; then
echo "TCTI environment variable not set; using default /dev/tpmrm0"
TCTI=device:/dev/tpmrm0
fi

if [[ -z "$TPM2TOOLS_TCTI" ]]; then
echo "TPM2TOOLS_TCTI environment variable not set; using default /dev/tpmrm0"
TPM2TOOLS_TCTI=device:/dev/tpmrm0
fi

if [[ -z "$TPM2OPENSSL_TCTI" ]]; then
echo "TPM2OPENSSL_TCTI environment variable not set; using default /dev/tpmrm0"
TPM2OPENSSL_TCTI=device:/dev/tpmrm0
fi

# Check that tpm2-openssl provider is available
if ! openssl list -provider tpm2 -providers; then
echo "Please install the tpm2-openssl provider"
exit 1
fi

function usage {
echo "Usage: $0 [--output OUTPUT_DIR][--pwd CA_PASSWORD]"
exit 0
}

while [[ $# -gt 0 ]]; do
case $1 in
-o|--output)
shift
if [[ $# -gt 0 ]]; then
OUTPUTDIR="$1"
shift
else
echo "Missing path to output directory"
usage
fi
;;
-p|--pwd)
shift
if [[ $# -gt 0 ]]; then
CA_PWD="$1"
shift
else
echo "Missing password"
usage
fi
;;
*)
# Ignore unknown options
shift
;;
esac
done

# If the output directory is not set, create a temporary directory to output the
# certificates
if [[ -z "$OUTPUTDIR" ]]; then
TEMPDIR=$(mktemp -d)
OUTPUTDIR="${TEMPDIR}/certs"
mkdir -p ${OUTPUTDIR}
fi

echo "Writing the certificates to the directory ${OUTPUTDIR}"

# Generate IAK/IDevID CA certificates
mkdir -p ${OUTPUTDIR}/root

# Copy CA configuration to output directory
CA_CONF=${OUTPUTDIR}/ca.conf
cp ${GIT_CA_CONF} ${OUTPUTDIR}/ca.conf

ROOT_CA_DIR=${OUTPUTDIR}/root
INTERMEDIATE_CA_DIR=${OUTPUTDIR}/intermediate

# Replace the output directory path accordingly
sed -i "s|REPLACE_ROOT_CA_DIR|${ROOT_CA_DIR}|" ${CA_CONF}
sed -i "s|REPLACE_INTERMEDIATE_CA_DIR|${INTERMEDIATE_CA_DIR}|" ${CA_CONF}

pushd ${OUTPUTDIR}
mkdir -p root root/crl root/certs
pushd root
touch index.txt
echo 1000 > serial

# Create private key for root CA certificate
openssl genrsa \
-aes256 \
-passout pass:${CA_PWORD} \
-out private.pem 4096

# Create self-signed root CA certificate
openssl req \
-config ${CA_CONF} \
-subj "/C=US/ST=MA/L=Lexington/O=Keylime Tests/CN=Keylime Test Root CA" \
-key private.pem \
-passin pass:${CA_PWORD} \
-new \
-x509 \
-days 9999 \
-sha384 \
-extensions v3_ca \
-out cacert.pem
popd

# Create intermediate CA keys and certificate
mkdir -p intermediate
pushd intermediate
mkdir certs csr crl
touch index.txt
echo 1000 > serial

# Create private keys for intermediary CA
openssl genrsa \
-aes256 \
-passout pass:${CA_PWORD} \
-out private.pem 4096

# Create CSR for the intermediate CA
openssl req \
-config ${CA_CONF} \
-subj "/C=US/ST=MA/L=Lexington/O=Keylime Tests/CN=Keylime Test Intermediate CA" \
-key private.pem \
-passin pass:${CA_PWORD} \
-new \
-sha256 \
-out csr/intermediate.csr.pem

# Create certs and cert chain for the intermediate CA
openssl ca \
-config ${CA_CONF} \
-extensions v3_intermediate_ca \
-keyfile ${ROOT_CA_DIR}/private.pem \
-cert ${ROOT_CA_DIR}/cacert.pem \
-days 9998 \
-notext \
-md sha384 \
-batch \
-in csr/intermediate.csr.pem \
-passin pass:${CA_PWORD} \
-out cacert.pem
popd
cat intermediate/cacert.pem root/cacert.pem \
> cert-chain.pem
popd

mkdir ${OUTPUTDIR}/ikeys
pushd ${OUTPUTDIR}/ikeys

# The templates used in order to regenerate the IDevID and IAK keys are
# taken from the TCG document "TPM 2.0 Keys for Device Identity and
# Attestation:
#
# https://trustedcomputinggroup.org/wp-content/uploads/TPM-2p0-Keys-for-Device-Identity-and-Attestation_v1_r12_pub10082021.pdf
#
# The template H-1 is used here.
#
# The unique values piped in via xxd for the '-u -' parameter are 'IDevID' and
# 'IAK' strings in hex, as defined in section 7.3.1
#
# The attributes (-a) and algorithms (-g, -G) are specified in 7.3.4.1 Table
# 3 and 7.3.4.2 Table 4 respectively
#
# The policy values (-L) are specified in 7.3.6.6 Table 19

# Regenerate IDevID within TPM
echo -n 494445564944 | xxd -r -p | tpm2_createprimary -C e \
-g sha256 \
-G rsa2048:null:null \
-a 'fixedtpm|fixedparent|sensitivedataorigin|userwithauth|adminwithpolicy|sign' \
-L 'ad6b3a2284fd698a0710bf5cc1b9bdf15e2532e3f601fa4b93a6a8fa8de579ea' \
-u - \
-c idevid.ctx -o idevid.pub.pem

# Persist IDevID and save handle index
tpm2_evictcontrol -c idevid.ctx | grep -o '0x.*$' > idevid.handle

# Create CSRs for the IDevID and sign with the intermediate CA
openssl req \
-config ${CA_CONF} \
-subj "/C=US/ST=MA/L=Lexington/O=Keylime Tests/CN=Keylime IDevID" \
-provider tpm2 \
-provider default \
-propquery '?provider=tpm2' \
-new \
-key handle:$(cat idevid.handle) \
-out ${INTERMEDIATE_CA_DIR}/csr/idevid.csr.pem

openssl ca \
-config ${CA_CONF} \
-name CA_intermediate \
-extensions server_cert \
-days 999 \
-notext \
-passin pass:${CA_PWORD} \
-batch -md sha384 \
-in ${INTERMEDIATE_CA_DIR}/csr/idevid.csr.pem \
-out ${OUTPUTDIR}/idevid.cert.pem

# Evict the persisted IDevID key using the handle and cleanup any transient
# object
tpm2_evictcontrol -c $(cat idevid.handle)
tpm2_flushcontext -t -l -s

# Regenerate IAK within TPM
echo -n 49414b | xxd -r -p | tpm2_createprimary -C e \
-g sha256 \
-G rsa2048:rsapss-sha256:null \
-a 'fixedtpm|fixedparent|sensitivedataorigin|userwithauth|adminwithpolicy|sign|restricted' \
-L '5437182326e414fca797d5f174615a1641f61255797c3a2b22c21d120b2d1e07' \
-u - \
-c iak.ctx -o iak.pub.pem

# Persist IAK and save handle index
tpm2_evictcontrol -c iak.ctx | grep -o '0x.*$' > iak.handle

# Create CSRs for the IAK and sign with the intermediate CA
openssl req \
-config ${CA_CONF} \
-subj "/C=US/ST=MA/L=Lexington/O=Keylime Tests/CN=Keylime IAK" \
-provider tpm2 \
-provider default \
-propquery '?provider=tpm2' \
-new \
-key handle:$(cat iak.handle) \
-out ${INTERMEDIATE_CA_DIR}/csr/iak.csr.pem

openssl ca \
-config ${CA_CONF} \
-name CA_intermediate \
-extensions server_cert -days 999 \
-notext \
-passin pass:${CA_PWORD} \
-batch \
-md sha384 \
-in ${INTERMEDIATE_CA_DIR}/csr/iak.csr.pem \
-out ${OUTPUTDIR}/iak.cert.pem

# Evict the persisted IAK key using the handle and cleanup any transient
# object
tpm2_evictcontrol -c $(cat iak.handle)
tpm2_flushcontext -t -l -s

# Convert certs to DER
openssl x509 \
-inform PEM \
-outform DER \
-in ${OUTPUTDIR}/idevid.cert.pem \
-out ${OUTPUTDIR}/idevid.cert.der

openssl x509 \
-inform PEM \
-outform DER \
-in ${OUTPUTDIR}/iak.cert.pem \
-out ${OUTPUTDIR}/iak.cert.der
popd

Loading

0 comments on commit 82c1f6c

Please sign in to comment.