TPM Remote attestation allows a remote server to “trust” that a specific TPM has signed some data or assert system state. Its cryptographically secure way to transfer secrets and do many more things.
The first step to establish trust is to setup a way a remote system can “prove” that a specific TPM is resident on a client. Once thats established through a specific flow, a remote server can repeatedly ‘verify’ the clients system state though various mechanisms like Quote/Verify though PCR values.
This article and accompanying git repo here includes client/server to do many things.
It basically an implementation in go of
you’ll find the source here
Note: there are two branches to this repository: push
and pull
The main difference between them is which side initiates communication to attest a TPM.
In the push
model, the verifier
is a remote server which makes an outbound API call to the TPM device (attestor
). The TPM device now performs remote attestation but is driven by the the API calls from the remote server.
In the pull
model, the verifier
is a remote server which receives an outbound API call from the TPM device (attestor
). The TPM device is in control of when to initiate and perform remote attestation.
Attestation:
( Images taken from Remote Attestation )
Quote/Verify:
EventLog
NOTE the code and procedure outlined here is NOT supported by google.
You can use this standalone to setup a gRPC client/server for remote attestation.
There are two parts:
attestor
: a gRPC
server which accepts connections from a verifier, performs remote attestation, quote/verify and then then securely receives a sealed key from a verifier. The key is distributed such that it can only get loaded or decoded on the attestor that has the TPM
verifier
: a gRPC
client which connects to the corresponding attestor, proves it owns a specific TPM and then sends a sealed Key that can only be decoded by that client.
As you can see, the whole protocol is rather complicated but hinges on being able to trust the initial Endorsement Key. As mentioned, this is normally done by validating that the EndorsementPublic certificate is infact real and signed by a 3rd party (eg, the manufacturer of the TPM). In the case of google’s shielded vTPM, it is signed by google’s subordinate CA and includes information about the VM’s instance_id value. This protocol also “validates” the PlatformCA which itself includes a reference (serial# reference) to the EndorsementKey. I suppose it can contain the hash of the EKcert as another attribute…
also see
We will use a GCP Shielded VM for these tests
First create two VMs
gcloud compute instances create attestor \
--zone=us-central1-a --machine-type=e2-medium --no-service-account --no-scopes \
--image=debian-11-bullseye-v20211105 --image-project=debian-cloud \
--shielded-secure-boot --shielded-vtpm --shielded-integrity-monitoring
gcloud compute instances create verifier \
--zone=us-central1-a --machine-type=e2-medium --no-service-account --no-scopes \
--image=debian-11-bullseye-v20211105 --image-project=debian-cloud \
--shielded-secure-boot --shielded-vtpm --shielded-integrity-monitoring
On each, install go 1.16+
and setup libtspi-dev
, gcc
(apt-get update && apt-get install gcc libtspi-dev
)
apt-get update
apt-get install libtspi-dev wget gcc -y
wget https://golang.org/dl/go1.17.linux-amd64.tar.gz
rm -rf /usr/local/go && tar -C /usr/local -xzf go1.17.linux-amd64.tar.gz
the client VM, edit /etc/hosts
and set the value of verify.esodemoapp2.com
to the IP of the server (in my case, its 10.128.0.58
)
10.128.0.58 verify.esodemoapp2.com
ofcourse you can use any hostname here but the certificated provided in this repo matches the SAN values for TLS.
Now test the client-server by transmitting both an RSA and AES key.
On startup, the verifier will:
Begin Remote Attestation
End Remote Attestation
Begin Quote/Verify
End Quote/Verify
Begin Sealed Transfer (PushSecret)
End Sealed Transfer
Begin Unrestricted SigningKey Transfer (PullSecret)
End Unrestricted SigningKey Transfer
go run src/grpc_attestor.go --grpcport :50051 \
--unsealPcrs=0,7 \
--caCertTLS certs/CA_crt.pem \
--servercert certs/server_crt.pem \
--serverkey certs/server_key.pem \
-useFullAttestation --readEventLog \
--platformCertFile certs/platform_cert.der \
--v=10 -alsologtostderr
go run src/grpc_verifier.go --importMode=AES --uid 369c327d-ad1f-401c-aa91-d9b0e69bft67 --readEventLog \
-aes256Key "G-KaPdSgUkXp2s5v8y/B?E(H+MbQeThW" \
--host verify.esodemoapp2.com:50051 \
--expectedPCRMapSHA256 0:24af52a4f429b71a3184a6d64cddad17e54ea030e2aa6576bf3a5a3d8bd3328f,7:3d91599581f7a3a3a1bb7c7a55a7b8a50967be6506a5f47a9e89fef756fab07a \
--expectedPCRMapSHA1 0:0f2d3a2a1adaa479aeeca8f5df76aadc41b862ea \
--caCertTLS certs/CA_crt.pem --caCertIssuer certs/CA_crt.pem --caKeyIssuer certs/CA_key.pem --platformCA certs/CA_crt.pem \
--readEventLog \
--useFullAttestation \
--v=10 -alsologtostderr
go run src/grpc_attestor.go --grpcport :50051 \
--unsealPcrs=0,7 \
--caCertTLS certs/CA_crt.pem \
--servercert certs/server_crt.pem -useFullAttestation --readEventLog \
--serverkey certs/server_key.pem --platformCertFile certs/platform_cert.der \
--v=10 -alsologtostderr
go run src/grpc_verifier.go --importMode=RSA --uid 369c327d-ad1f-401c-aa91-d9b0e69bft67 \
--expectedPCRMapSHA256 0:24af52a4f429b71a3184a6d64cddad17e54ea030e2aa6576bf3a5a3d8bd3328f,7:3d91599581f7a3a3a1bb7c7a55a7b8a50967be6506a5f47a9e89fef756fab07a \
--expectedPCRMapSHA1 0:0f2d3a2a1adaa479aeeca8f5df76aadc41b862ea \
--rsaCert=certs/tpm_client.crt \
--readEventLog --useFullAttestation \
--caCertTLS certs/CA_crt.pem --caCertIssuer certs/CA_crt.pem --caKeyIssuer certs/CA_key.pem --platformCA certs/CA_crt.pem \
--rsaKey=certs/tpm_client.key --host verify.esodemoapp2.com:50051 \
--v=10 -alsologtostderr
Please see the following for background on the eventlog and how to use it
Note, on GCP Shielded VM, the default
PCR0
value is:
# tpm2_pcrread sha1:0+sha256:0
sha1:
0 : 0x0F2D3A2A1ADAA479AEECA8F5DF76AADC41B862EA
sha256:
0 : 0x24AF52A4F429B71A3184A6D64CDDAD17E54EA030E2AA6576BF3A5A3D8BD3328F
The platform certificate used in this protocol is just a sample, static one tied to a ShieldedVM’s EKCert serial number.
I did this because i do not know how to generate a platform cert in go. Instead i used NSA’s Platform Attribute Certificate Creator (paccor) in java to create the cert separately.
What this means is we just make believe/pretend that the platform cert is valid by statically comparing the serialnumbers. In reality the verifier should check the certificate serial number and that a valid privacy ca signed the cert..
Note a sample serial number that is in the EKCert
tpm2_nvread -o ekcert.der 0x01c00002
openssl x509 -in ekcert.der -inform DER -outform PEM -out ekcert.pem
# openssl x509 -in ekcert.der -inform DER -outform PEM -out ekcert.pem
openssl x509 -in ekcert.pem -text
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
01:43:f2:f9:3e:d0:12:42:d6:86:88:fb:48:ba:7c:b9:9e:dd:50
Signature Algorithm: sha256WithRSAEncryption
Issuer: C = US, ST = California, L = Mountain View, O = Google LLC, OU = Cloud, CN = "tpm_ek_v1_cloud_host-signer-0-2021-10-12T04:22:11-07:00 K:1, 3:nbvaGZFLcuc:0:18"
and the encoded reference of the same in the platform_cert.der
$ openssl asn1parse -inform DER -in certs/platform_cert.der
0:d=0 hl=4 l=1268 cons: SEQUENCE
4:d=1 hl=4 l= 988 cons: SEQUENCE
8:d=2 hl=2 l= 1 prim: INTEGER :01
11:d=2 hl=3 l= 218 cons: SEQUENCE
...
.
121:d=7 hl=2 l= 88 cons: SET
123:d=8 hl=2 l= 86 cons: SEQUENCE
125:d=9 hl=2 l= 3 prim: OBJECT :commonName
130:d=9 hl=2 l= 79 prim: UTF8STRING :tpm_ek_v1_cloud_host-signer-0-2021-10-12T04:22:11-07:00 K:1, 3:nbvaGZFLcuc:0:18
211:d=4 hl=2 l= 19 prim: INTEGER :0143F2F93ED01242D68688FB48BA7CB99EDD50
232:d=2 hl=2 l= 93 cons: cont [ 0 ]
This links the platform cert with that specific EKCert
You can verify the Platform cert was signed by a given CA by using [go-attestation.attributecert.AttributeCertificate.CheckSignatureFrom](https://pkg.go.dev/github.com/google/go-attestation@v0.3.2/attributecer t#AttributeCertificate.CheckSignatureFrom)
3.2 Platform Certificate
This section contains the format for a Platform Certificate conforming to version 1.0 of this specification.
The Platform Certificate makes the assertions listed in section 2.1.6. This certificate format
adheres to RFC 5755 [11] and all requirements and limitations from that specification apply unless otherwise noted.
This is just an academic exercise (so do not use the code as is). However, some applications of this
If you use a GCP Confidential Compute VM for the attestor, use the pcr values it currently holds
gcloud compute instances create attestor-cc --zone=us-central1-a --machine-type=n2d-standard-2 \
--confidential-compute --maintenance-policy=TERMINATE \
--image=ubuntu-2004-focal-v20210927 --image-project=confidential-vm-images \
--no-service-account --no-scopes \
--shielded-secure-boot --shielded-vtpm --shielded-integrity-monitoring
tpm2_pcrread sha1:0,7+sha256:0,7
sha1:
0 : 0xC032C3B51DBB6F96B047421512FD4B4DFDE496F3
7 : 0x45B6A836BDC555783626C9E4E6234AC692F76B0B
sha256:
0 : 0x0F35C214608D93C7A6E68AE7359B4A8BE5A0E99EEA9107ECE427C4DEA4E439CF
7 : 0xDD0276B3BF0E30531A575A1CB5A02171EA0AD0F164D51E81F4CD0AB0BD5BAADD
go run src/grpc_verifier.go --importMode=RSA --uid 369c327d-ad1f-401c-aa91-d9b0e69bft67 \
--expectedPCRMapSHA256 0:0f35c214608d93c7a6e68ae7359b4a8be5a0e99eea9107ece427c4dea4e439cf,7:dd0276b3bf0e30531a575a1cb5a02171ea0ad0f164d51e81f4cd0ab0bd5baadd \
--expectedPCRMapSHA1 0:c032c3b51dbb6f96b047421512fd4b4dfde496f3 \
--rsaCert=certs/tpm_client.crt \
--readEventLog --useFullAttestation \
--caCertTLS certs/CA_crt.pem --caCertIssuer certs/CA_crt.pem --caKeyIssuer certs/CA_key.pem \
--rsaKey=certs/tpm_client.key --host verify.esodemoapp2.com:50051 \
--v=10 -alsologtostderr
This site supports webmentions. Send me a mention via this form.