title | summary | image |
---|---|---|
tpm2-attest: Simple TPM2 Remote Attestation |
tpm2-attest is a simple way to have an untrusted Linux machine generate signed TPM quotes, validate those quotes and endorsement keys on a remote attestation server, and seal secret messages that will only be unsealable on that specific TPM. |
images/tpm-header.jpg |
When the user wants to connect to another computer over the network, they typicaly authenticate with a password and some sort of two factor token to prove to the remote system that they are authorized to make the connection. In high assurance applications, however, it is also important that the local computer be able to attest to the remote server that the local computer itself is both authorized and is also in a known configuration.
The TPM provides a mechanism to do this sort of remote attestation,
similar to the way that the disk encryption keys are "sealed" based
on the PCRs and only decrypted if the platform configuration matches
the sealed values. The tpm2-tools
package has many of the pieces,
but it is at too low a level for humans to use. Other parts of the
validation exist in the openssl
package, but again are not easily
used and require format conversions from the TPM formats.
tpm2-attest
attempts to wrap all of the various parts of
those two packages into a simple script that provides the four
main attestation functions: sign a quote, validate a signed quote,
seal a secret for a specific TPM, and unseal it with that TPM.
Related to this is attest-enroll
, a script that
enrolls a device (e.g., a laptop, a server, etc.) given just its
TPM's endorsement key's public key (EKpub
) and a name. Enrollment
can produce and encrypt to that EKpub
any number of long-term
secrets that are later sent to that device during successful
attestation.
-
Enroll:
- extract
EKpub
, pick a device name - run
attest-enroll
(typically via an HTTP API) with thatEKpub
and name
- extract
-
Attest:
- Client:
tpm2-attest > quote.tar
- Client: Send
quote.tar
to server (typically via an HTTP API) - Server:
tpm2-attest verify quote.tar | attest-verify
to verify the client's state - Server:
tpm2-attest seal quote.tar < enrolled-secrets.tar > cipher.bin
- Server: Send
cipher.bin
to client - Client:
tpm2-attest unseal < cipher.bin > enrolled-secrets.tar
- Client: use
tpm2-recv
to decrypt long-term secrets inenrolled-secrets.tar
- Client:
sequenceDiagram
participant TPM
participant Client
participant Server as Attestation Server
participant DB as Attestation Database
TPM->>Client: EK, AK, Quote
Client->>Server: EK, AK, Quote, eventlog
Server->>DB: Hash EKpub, eventlog
DB->>Server: TK and encrypted data
Server->>Client: reply.tar: CK, TK, data
Client->>TPM: activatecredential with AK
TPM->>Client: Decrypted CK
Client->>TPM: Load TK
Client->>TPM: TK Encrypted data
TPM->>Client: Decrypted data
Client->>Server: Success
The protocol requires a one round-trip between the local machine
(the client) and the remote attestation server), and all
comunication between the Client and the Server can be in the clear.
There is no sensitive data exchanged -- the quote.tar
file contains
only public keys and PCR values that are essentially public, and the
cipher.bin
reply is encrypted with the TPM's Endorsement Key, so it
should only be unsealable by that specific TPM.
A MITM could substitute a different EK/AK pair, although this does not allow them to masquarade as the TPM of the attesting machine since they do not have the EK for that TPM, and the real TPM won't be able to decrypt the response from the attestation server since it would be encrypted with the wrong EK.
The keys involved are:
- CA Root, stored hopefully securely by the CA
- TPM Manufacturer key, a signing-only key signed by the CA Root, and stored hopefully securely by the OEM
- TPM Endorsement key (
EK
), an encryption key, generated in the TPM(?) and stored in the TPM hardware device - TPM Endorsement certificate (
ek.crt
), signed by the TPM manufacturer, often stored in the TPM NVRAM - Attestation Key (
AK
), a ephemeral signing-only key generated by the TPM, but not signed by it (for inexplicable reasons), used to sign the PCR quotes - Credential Key (
CK
), an ephemeral symmetric encryption key used to protect the reply from the server, encrypted with theEK
and tied to theAK
so that only that TPM will decrypt it, and only if theAK
is a valid key. - Transport Key (
TK
), a long-term TPM duplicate key used to protect the attestation data. It is stored in the attestation database and encrypted with the client machine'sEK
, and has a policy that allows it to be used only once.
There are two protocols: enrollment, and attestation. Each protocol is one round trip.
sequenceDiagram
participant Admin
participant Server as Enrollment Server
participant DB as Attestation Database
Admin->>Server: client 'EKpub'<br/> `EKcert`<br/> hostname<br/> Other data
Note right of Server: validate `EKpub` against `EKcert`<br/> Generate TK
Server->>DB: `EKpub`<br/> hostname<br/> `TK` (encrypted with `EK`)
Note left of DB: Indexed by `sha256(EKpub)`
-
An administrator, or the client itself, sends the client's
EKpub
and desired hostname to the enrollment server. -
The enrollment server checks that the client's enrolled state does not exist, then it creates it.
See
sbin/attest-enroll
.
The enrolled state consists of secrets encrypted to the client's
EKpub
and cleartext metadata.
sequenceDiagram
participant TPM
participant Client
participant Server as Attestation Server
TPM->>Client: EKpub, Ephemeral AK
Client->>TPM: Time since epoch
TPM->>Client: Quote of all PCRs and time, signed with AK
Note right of Client: Extract eventlog
Client->>Server: quote.tar:<br/>EKpub and cert<br/> AK<br/> Quote (signed with AK)<br/> eventlog
-
Client creates an Attestation Key (
AK
), quotes all the PCRs and current time, and sends itsEKpub
,AKpub
, quote, and eventlog to the server. This is done withtpm2-attest quote > quote.tar
sequenceDiagram
participant Client
participant Server as Attestation Server
participant DB as Attestation Database
Client->>Server: quote.tar
Note right of Server: Validate signature on Quote
Note right of Server: Validate eventlog matches quote
Note right of Server: Validate time stamp is recent
Server->>DB: Hash EKpub, eventlog
Note left of DB: Validate policy on eventlog and PCRs
DB->>Server: TK (encrypted with EK)<br/> Attestation data (encrypted with TK)
Note right of Server: Create ephemeral credential key CK
Note right of Server: Encrypt TK (encrypted with EK) with CK
Note right of Server: makecredential with EK+AK and CK (no TPM required)
Server->>Client: reply.tar:<br/>Credential blob<br/>(CK, encrypted with the EK / AK)<br/> TK encrypted with EK and credential key<br/> Attestation data (encrypted with TK)
-
The server checks the quote, calls
TPM2_MakeCredential()
with theAKpub
as the activation object, theEKpub
as the key to encrypt to, and an AES-256 session key, and sends back the output as well as the enrolled state encrypted in that AES-256 session key. This is done withtpm2-attest verify | attest-verify | tpm2-attest seal
sequenceDiagram
participant TPM
participant Client
participant Server as Attestation Server
Server->>Client: reply.tar
Client->>TPM: activatecredential with AK
Note right of TPM: validate AK, decrypt with EK
TPM->>Client: Unsealed CK
Note right of Client: Decrypt TK (encrypted with EK) with CK
Client->>TPM: Load TK (encrypted with EK)
TPM->>Client: TK context
Client->>TPM: TK policy<br> Attestation data encrypted with TK
Note right of TPM: validate TK policy<br>Decrypt data with TK
TPM->>Client: Decrypted attestation data
Client->>Server: Optionally report success
The client recovers the AES-256 session key using
TPM2_ActivateCredential()
and then decrypts the secrets in its
enrolled state. This is done with:
tpm2-attest unseal
then
tpm2-recv
for each secret.
An optional second round-trip allows the client to prove possession
of the EK
and AK
, and this can be used for logging the client's
attestation status.
When the Server receives the quote file from the client, it runs:
tpm2-attest verify quote.tar $nonce
With this command the server will:
- Validates the SSL certificate chain on the client TPM EK cert to ensure that it came from a real TPM
- Validates that the quote is signed by the AK with the correct nonce (if the nonce is not checked, then this could be a replay attack by the Client)
- Server optionally consults its list of previously enrolled devices to verify that this EK is in an owner controlled machine
- Server optionally validates that the PCRs match the expected values
- Server optoinally validates that the TPM event log produces the set of PCR values in the quote
If the command fails, then something is likely wrong on the Client side and requires remediation. The Server should not proceed to sealing a secret for the Client.
Suprisingly, the Attestation Key is not signed by the Endorsement Key,
so the Server has to check the EK certificate to ensure that it came from
a real TPM. Additional, the Server must check the AK attributes to ensure
that it has fixedtpm
and sensitivedataorigin
set, which indicates that
the AK was generated inside the TPM. Even with these checks, the Server is
still trusting that the TPM hardware implements tpm2_activatecredential
with all of these checks correctly done, since the sealed data is encrypted
with the EK, not the AK. (Like many things with the TPM2, this is a really
baroque way to organize the keys).
Assuming the validation passed, the server can seal secret data such that only the TPM that produced the signed attestation will be able to unseal it, and has faith that the TPM will not unseal it if it has been reset (to prevent attacks that reboot into untrusted firmware):
cat secret.txt | tpm2-attest seal quote.tar > cipher.bin
With this command the Server will:
- Encrypt a secret message (which could be a disk encryption key, a network access token, or whatever) with the TPM's EK, along with the hash of the AK.
The Server then sends this encrypted blob to the Client.
Note that there is a verify-and-seal
that combines both the quote validation
and the sealing of the data to the attestation key in one step:
cat secret.txt | tpm2-attest seal quote.tar $nonce > cipher.bin
Once the Client receives the sealed blob from the Server, it attempts to unseal it with the Attestation Key context that is left over from the initial quote signing:
cat cipher.bin | tpm2-attest unseal ak.ctx > secret.txt
With this command, the Client and TPM will:
- Initiates an encrypted session with the TPM and sends the blob to it.
- The TPM checks that the hash of the AK matches one that it generated and that it hasn't rebooted since then. If these checks pass, the TPM uses its private EK to decrypt the blob.
- Client receives the secret message over the encrypted channel to the TPM
At this point the Client can use the shared secret to authenticate to the Server, a network, or decrypt it's disk, or whatever. The TPM is no longer involved.
A key part of the remote attestion is being able to trust that the TPM hardware
is produced by a TPM manufacturer. Much like SSL Certs for websites, the
TPM's Endorsement Key is signed by the OEM with their Intermediate CA,
which is signed by a Root CA. Unlike SSL, the Root CAs are often not in
the system's /etc/ssl/certs/
directory, and not easily accessible online.
Some OEMs publish them in datasheets
(ST TPM EK certificates),
some have online portals to select per-device intermediate certs
(Infineon Optiga certificates),
and some just say "Contact manufacturer for more details"
(Atmel/Microchip EK Configuration).
Luckily Microsoft has a CAB file with all of their approved TPM OEMs in their
guide to setting up shielded VMs.
These x509 certs are in DER format (and have a few odd ones),
so they have been converted to PEM and bundled into /etc/safeboot/certs/
for
validating the TPM attestations.
If you add your own TPM keys to the directory, you will need to re-build the symlinks
that OpenSSL uses for the -CApath
:
c_rehash /etc/safeboot/certs/
Unfortunately not all TPMs store their EK certs in the NVRAM;
some of them require an online query to the OEM to generate the certificate.
There is the tpm2_getmanufec
program that is supposed to help with this
process, although it hasn't been integrated into this tool yet.
An alternative is to sign the EK with a key under your own control
with tpm2-attest ek-sign
. This will produce ek.crt
, signed with
the safeboot key. The signing operation can be done out-of-band
on a different machine.
Usually the EK public components can be extracted from the TPM, signed,
and the resulting signed ek.crt
can be stored back into the TPM nvram.
Note that this will erase an existing OEM cert if you have one!
tpm2 createek -c /dev/null -f PEM -u ek.pem
tpm2-attest ek-sign < ek.pem > ek.crt /CN=device/OU=example.org/
tpm2 nvdefine -s 1500 0x1c00002
tpm2 nvwrite -i ek.crt 0x1c00002
Google Cloud's ShieldedVM service enables vTPM for the guests, although
it does not provide an EK in the NVRAM either.
The key can be retrieved out of band with these instructions,
or the public component can be read from the tpm2 createek
command
described above. Using the Google Cloud ShieldedVM lookup service
can function as an EKcert as far as establishing trust in an
instance's vTPM.
Since the quote does not contain any clear text information and the
response is sealed specifically for the TPM that generated the quote,
a simple http server can be used to perform the attestion verification.
A demo in sbin/attest-server
performs this, using a fixed set of PCRs
and a table of public key to secret mappings for the listed endorsement
keys.
On the server run:
./sbin/attest-server secrets.yaml
And on the client:
tpm2-attest attest http://server-name/ \
> /tmp/secret.txt \
|| echo "failed!"
It is often desirable to perform a remote attestion inside of an initrd
,
where there aren't fancy runtimes for Python or more advanced languages.
So the quote generation needs to be written assuming very limited resources,
as does the response unsealing.
The remote attestation server side could be implemented entirely in a more civilized language, especially since the Server does not require any TPM interaction at all -- all of its work is done in software and can be run as an ordinary user.
As an example of moving some functionality into better languages, the
tpm2-eventlog-validate
tool that parses the TPM2 event log and generates
expected PCR values is written in Python.
One of the big fears in the free software community was that TPM's would be used to lockdown the devices and implement DRM. That hasn't developed in general purpose computers and mjg59's TPM guide concludes with "the current state of technology doesn't make them useful for practical limitations of end-user freedom". There's a far bigger threat to user freedom in the locked-down world of mobile devices; currently most x86 machines allow rekeying with user keys, so the software (but not the firmware) is still under owner control.
Remote Attestation can be used bidirectionally as well - it allows the server to attest to the client that the machine is in a trustworthy state. This is perhaps an even more valuable use case: you might have fairly tight physical control of your personal machine, but a bare metal server in a data center is potentially open to attacks by the cloud operator as well as the previous tenants. Having attestations as to the firmware and the OS configuration can make it more trustable.
There is lots of traffic between the tpm2-attest
program and the TPM
during the attestation process, and the TPM is not a fast device.
Read the Endorsement Key (EK) and EK Certificate take a few hundred
miliseconds, signing the quote takes another few hundred, etc.
The process used to take around 20 seconds, since the TPM had to generate
a new RSA Attestation Key (AK) to sign the PCR quote, and generating an RSA
key requires finding large primes with certain values. The AK was replaced
with ECC, which is much faster to generate.
Creating a new one each time should not be necessary; several attestation protocols
use a pregenerated AK that is persistent in the TPM, except that opens up
a race condition between generating a quote and receiving the sealed
data. The quote includes the reboot count, but the sealed data
does not reference it, so the TPM will unseal it if the AK is still
valid, even if an attacker has rebooted into an untrustworthy state
inbetween generating the quote and receiving the sealed response.
By creating an ephemeral AK (with the stclear
bit set in the
attributes), the TPM will not allow it to be persisted and will refuse
to reload it when the reboot counter increments.
The Discrete TPM is potentially a hardware weakpoint; a physically proximate adversary could remove the TPM from a machine and connect it to an untrusted device and then masquarade as the device to which the TPM had been connected. This would also potentially allow them to extract any sealed disk encryption keys, as described on the threat model page, and is one of the advantages of an fTPM inside the Management Engine.
A proximate attacker could also interfere with the LPC or i2c bus of a Discrete TPM using something like the TPM Genie, which allow them to both modify the hashes sent to the TPM during PCR extension operations, and read the unsealed secrets when they are returned if the TPM didn't support secret sessions.
However, the fTPM is a pure-software application inside the ME and potentially allows an attacker with code execution on the ME to find the sealing secrets that are used to protect the TPM keys in the ME NVRAM, which would allow attacks against the quoting and attestation process.