#!/bin/bash

# Assumes HIRS is already installed
# Dependencies:
#  openssl, version 1.0.2 (must download from source)
#  tpm_module

# Download and install latest version of openssl from source, using these steps:
# cd /usr/local/src
# wget https://www.openssl.org/source/openssl-1.0.2-latest.tar.gz
# tar -zxf openssl-1.0.2-latest.tar.gz
# cd openssl-1.0.2*
# ./config
# make depend
# make
# make install
# mv /usr/bin/openssl /root
# ln -s /usr/local/ssl/bin/openssl /usr/bin/openssl

# The TPM only gives us the public key modulus, not a properly formatted key
PUBEK_MOD=$(tpm_module -m 29 -nr -d -t ek -z -d)
rc=$?
if [ "$rc" != "0" ]; then
    echo "Attempt to access the TPM's public Endorsement Key was unsuccessful"
    echo "Exiting"
    exit $rc;
fi

# Check user's permissions
if [ ! -w $(pwd) ] ; then
    echo "This user does not have permissions to write to this directory: $(pwd)"
    echo "Exiting"
    exit 1
fi

mkdir -p certs
cd certs

EKCERT_PATH="$(pwd)/ek.crt"
CAKEY_PATH="$(pwd)/ca.key"
CACERT_PATH="$(pwd)/ca.crt"

# Create the asn.1 definition file used to recreate the public key using the modulus
cat << @EOF > def.asn1
# Start with a SEQUENCE
asn1=SEQUENCE:pubkeyinfo

# pubkeyinfo contains an algorithm identifier and the public key wrapped
# in a BIT STRING
[pubkeyinfo]
algorithm=SEQUENCE:rsa_alg
pubkey=BITWRAP,SEQUENCE:rsapubkey

# algorithm ID for RSA is just an OID and a NULL
[rsa_alg]
algorithm=OID:rsaEncryption
parameter=NULL

# Actual public key: modulus and exponent
[rsapubkey]
n=INTEGER:0x$PUBEK_MOD

e=INTEGER:0x010001
@EOF

# openssl commands return v1 certificates by default
# create a .ext file to specify that we want v3
cat << @EOF > v3.ext
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
@EOF

# Create endorsement key given the asn1 file (DER is the default)
openssl asn1parse -genconf def.asn1 -out ek.der -noout
rm def.asn1

# Convert endorsement key from DER to PEM
openssl rsa -pubin -in ek.der -inform DER -out ek.pem -outform PEM
rm ek.der

# Create self-signed CA certificate
openssl req -newkey rsa:2048 -nodes -keyout $CAKEY_PATH -x509 -days 365 -out $CACERT_PATH \
-subj "/CN=www.example.com"

# openssl needs a private key to create a new certificate signing request
# we only have the public endorsement key, so create a temporary key pair here
openssl req -newkey rsa:2048 -out temp.csr -nodes -keyout temp.key -subj "/CN=www.example.com"
rm temp.key

# Create the certificate here, forcing the use of our endorsement key (this means our temp key isn't used anymore
errormessage=`openssl x509 -req -days 365 -in temp.csr -extfile v3.ext -CAcreateserial -CAkey $CAKEY_PATH -CA $CACERT_PATH -out $EKCERT_PATH -force_pubkey ek.pem 2>&1`
rc=$?
rm v3.ext temp.csr ek.pem
if [ "$rc" != "0" ]; then
    echo $errormessage | grep -q "unknown option -force_pubkey" && echo "ERROR: The option 'force_pubkey' is required, but was not found for this installation of openssl x509. Please install a newer version (1.0.2+) from source" || echo $errormessage
    echo "Cleaning up..."
    rm $CAKEY_PATH $CACERT_PATH
    cd ..
    rmdir certs --ignore-fail-on-non-empty
    exit $rc
fi
rm ca.srl

openssl x509 -text -in $EKCERT_PATH

echo "SUCCESS: EK cert created successfully at: $EKCERT_PATH"
echo "         CA key found at:                 $CAKEY_PATH"
echo "         self-signed CA cert found at:    $CACERT_PATH"
echo