Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@dnoliver
Last active October 12, 2020 12:47
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dnoliver/388303c94639b763e9f120e2cbcccf8f to your computer and use it in GitHub Desktop.
Save dnoliver/388303c94639b763e9f120e2cbcccf8f to your computer and use it in GitHub Desktop.
Custom Application Using TPM PKCS11

Custom Application Integration with TPM2 PKCS11

Example on how to use TPM 2.0 keys to stablish a Mutual TLS connection. TPM 2.0 keys are accessed using the TPM2 PKCS#11 module.

Setup PKI and run a test with openssl s_server and openssl s_client

[test@fedora-server ~]$ sudo ./tls-pkcs11-test.sh

Then, test with the custom NodeJS application.

Start the server in background:

[test@fedora-server ~]$ sudo openssl s_server -CAfile ./tls-server/ca.crt -cert ./tls-server/server.crt -key ./tls-server/server.key -Verify 1 <<< '1' &

Get the private key id:

[test@fedora-server ~]$ sudo tpm2_ptool listobjects --label tls
- CKA_CLASS: CKO_PRIVATE_KEY
  CKA_ID: '37303964363438613061376363363763'
  CKA_KEY_TYPE: CKK_RSA
  CKA_LABEL: ''
  id: 1
- CKA_CLASS: CKO_PUBLIC_KEY
  CKA_ID: '37303964363438613061376363363763'
  CKA_KEY_TYPE: CKK_RSA
  CKA_LABEL: ''
  id: 2

Run the NodeJS application from the host:

[test@fedora-server ~]$ sudo OPENSSL_CONF=./ossl.cnf node tls.js pkcs11 37303964363438613061376363363763 ./tls-client/ca.crt ./tls-client/client.crt localhost 4433
Connection authorized by a Certificate Authority.

Run the NodeJS application from the container:

[test@fedora-server ~]$ docker build . -t test
[test@fedora-server ~]$ docker run --rm --device /dev/tpmrm0 --volume /etc/tpm2_pkcs11/:/etc/tpm2_pkcs11 --volume "$PWD":/root/test --net host test bash -c "OPENSSL_CONF=./ossl.cnf node tls.js pkcs11 37303964363438613061376363363763 ./tls-client/ca.crt ./tls-client/client.crt localhost 4433"
Connection authorized by a Certificate Authority.

On successful connection, the openssl s_server will display the following output:

verify depth is 1, must return a certificate
Using default temp DH parameters
ACCEPT
depth=1 CN = Easy-RSA CA
verify return:1
depth=0 C = US, ST = Oregon, L = Hillsboro, O = Intel Corp, OU = Internet of Things Group, CN = fedora-server.mshome.net
verify return:1
DONE
shutdown accept socket
shutting down SSL
CONNECTION CLOSED
   0 items in the session cache
   0 client connects (SSL_connect())
   0 client renegotiates (SSL_connect())
   0 client connects that finished
   1 server accepts (SSL_accept())
   0 server renegotiates (SSL_accept())
   1 server accepts that finished
   0 session cache hits
   0 session cache misses
   0 session cache timeouts
   0 callback cache hits
   0 cache full overflows (128 allowed)
FROM fedora:latest
RUN dnf install -y tpm2-pkcs11 tpm2-pkcs11-tools tpm2-tools gnutls-utils openssl-pkcs11 nodejs
VOLUME /etc/tpm2_pkcs11
VOLUME /root/test
WORKDIR /root/test
CMD bash
# docker run \
# --rm \
# --name test \
# -ti \
# --device /dev/tpmrm0 \
# --volume /etc/tpm2_pkcs11/:/etc/tpm2_pkcs11 \
# --volume "$PWD":/root/test \
# --net host \
# test bash
openssl_conf = openssl_init
[openssl_init]
engines = engine_section
[engine_section]
pkcs11 = pkcs11_section
[pkcs11_section]
engine_id = pkcs11
PIN=userpin
init = 0
[ req ]
distinguished_name = req_dn
string_mask = utf8only
utf8 = yes
[ req_dn ]
commonName = Mr Test Harness
#!/bin/bash
set -euxo pipefail
# WARNING: Clear the TPM and deletes the PKCS11 DB
# REQUIRES:
# dnf install -y tpm2-pkcs11 tpm2-pkcs11-tools tpm2-tools gnutls-utils
echo "PKI Setup"
echo "========="
rm -fr pki || true
mkdir -p pki
cd pki
# Download Easy RSA
wget https://github.com/OpenVPN/easy-rsa/releases/download/v3.0.5/EasyRSA-nix-3.0.5.tgz \
-O EasyRSA-nix-3.0.5.tgz
tar -zxvf EasyRSA-nix-3.0.5.tgz
cd EasyRSA-3.0.5
# Create PKI and Initial CA
./easyrsa init-pki
echo -ne '\n' | ./easyrsa build-ca nopass
# Generate Server Certs and Artifacts
./easyrsa build-server-full server nopass
cd ../../
echo "TLS Server Setup"
echo "================"
echo
rm -fr tls-server || true
mkdir -p tls-server
cd tls-server
# Configure Server
cp ./../pki/EasyRSA-3.0.5/pki/private/server.key .
cp ./../pki/EasyRSA-3.0.5/pki/issued/server.crt .
cp ./../pki/EasyRSA-3.0.5/pki/ca.crt .
cd ..
echo "TLS Client Setup"
echo "================"
echo
rm -fr tls-client || true
mkdir tls-client
cd tls-client
cat > client.cnf << EOF
[ req ]
default_bits = 2048
distinguished_name = req_distinguished_name
prompt = no
[ req_distinguished_name ]
C = US
ST = Oregon
L = Hillsboro
O = Intel Corp
OU = Internet of Things Group
CN = $(hostname)
EOF
# Create the TPM2 PKCS11 Key
export TPM2TOOLS_TCTI="device:/dev/tpmrm0"
export TPM2_PKCS11_TCTI="device:/dev/tpmrm0"
export TPM2_PKCS11_STORE=/etc/tpm2_pkcs11
export TPM2_PKCS11_LOG_LEVEL=0
rm ${TPM2_PKCS11_STORE} -fr || true
mkdir -p ${TPM2_PKCS11_STORE} || true
tpm2_clear
tpm2_ptool init
tpm2_ptool addtoken --pid=1 --sopin=sopin --userpin=userpin --label=tls
tpm2_ptool addkey --algorithm=rsa2048 --label=tls --userpin=userpin
tpm2_ptool config --key tcti --value "device:/dev/tpmrm0" --label=tls
# Create Certificate Signing Request
CKA_ID=$(tpm2_ptool listobjects --label tls | grep CKA_ID | uniq | awk '{ gsub("\047","", $2); print $2}' | sed 's/.\{2\}/%&/g')
openssl req -new -engine pkcs11 -keyform engine \
-key "pkcs11:id=${CKA_ID};type=private;pin-value=userpin" \
-config client.cnf -out client.csr
cd ..
echo "Generate Client Certificate"
echo "==========================="
echo
# Sign Certificate Signing Request
cd ./pki/EasyRSA-3.0.5/
./easyrsa import-req ./../../tls-client/client.csr client
echo -ne 'yes' | ./easyrsa sign-req client client
# Configure Client
cp ./pki/issued/client.crt ./../../tls-client/
cp ./pki/ca.crt ./../../tls-client/
cd ../../
echo "Start TLS Server"
echo "================"
cd tls-server
openssl s_server -CAfile ca.crt -cert server.crt -key server.key -Verify 1 <<< '1' &
SERVER_PID=$!
sleep 1
cd ..
echo "Start TLS Client"
echo "================"
cd tls-client
openssl s_client -engine pkcs11 -keyform engine -key "pkcs11:id=${CKA_ID};type=private;pin-value=userpin" -CAfile ca.crt -cert client.crt <<< 'Q'
var tls = require('tls'),
fs = require('fs');
var args = process.argv.slice(2);
if (args.length != 6) {
console.log('Usage: [OPENSSL_CONF=ossl.cnf] node tls.js ENGINE CKA_ID CA_PATH CERT_PATH HOST PORT');
process.exit(1);
}
var privateKeyEngine = args[0],
privateKeyIdentifier = args[1],
ca = args[2],
cert = args[3],
host = args[4],
port = args[5];
var tlsContext = tls.createSecureContext({
'privateKeyEngine': privateKeyEngine,
'privateKeyIdentifier': privateKeyIdentifier,
'ca': fs.readFileSync(ca),
'cert': fs.readFileSync(cert)
});
var options = {
host: host,
port: port,
secureContext: tlsContext,
// Necessary only if the server's cert isn't for "localhost".
checkServerIdentity: () => { return null; }
};
var conn = tls.connect(options, function() {
if (conn.authorized) {
console.log("Connection authorized by a Certificate Authority.");
} else {
console.log("Connection not authorized: " + conn.authorizationError)
}
console.log();
});
conn.on("data", function (data) {
console.log(data.toString());
conn.end();
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment