Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tests: Add script to generate IAK and IDevID certificates #883

Merged
merged 1 commit into from
Dec 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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) || {
echo "Please run this script from inside the rust-keylime repository tree"
exit 1
}

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

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

if [[ -z "$TCTI" ]]; then
ansasaki marked this conversation as resolved.
Show resolved Hide resolved
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_PWORD="$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}" > /dev/null || exit 1
mkdir -p root root/crl root/certs
pushd root > /dev/null || exit 1
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 > /dev/null || exit 1

# Create intermediate CA keys and certificate
mkdir -p intermediate
pushd intermediate > /dev/null || exit 1
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 > /dev/null || exit 1
cat intermediate/cacert.pem root/cacert.pem \
> cert-chain.pem
popd > /dev/null || exit 1

mkdir "${OUTPUTDIR}/ikeys"
pushd "${OUTPUTDIR}/ikeys" > /dev/null || exit 1

# 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 > /dev/null || exit 1

Loading
Loading