diff --git a/Attestation/Protocol-Four-Messages.png b/Attestation/Protocol-Four-Messages.png new file mode 100644 index 0000000..0102a54 Binary files /dev/null and b/Attestation/Protocol-Four-Messages.png differ diff --git a/Attestation/Protocol-Four-Messages.puml b/Attestation/Protocol-Four-Messages.puml new file mode 100644 index 0000000..07eb330 --- /dev/null +++ b/Attestation/Protocol-Four-Messages.puml @@ -0,0 +1,20 @@ +@startuml +participant TPM as T +participant Client as C +participant Server as S +participant ServerSimTPM as ST +title Four-message (two round trips) attestation protocol +C -> C: timestamp = gettimeofday(); +C --> T: TPM2_Quote(AK, set-of-all-PCRs, timestamp) +T --> C: quote=Signed_AK({hash-of-PCRs, misc, timestamp}) +C -> S: [ID], EKpub, [EKcert], AKpub,\nPCRs, eventlog, timestamp, quote +S -> S: check that timestamp is recent;\ndata = Lookup(EKpub, [EKcert], [ID]);\n[Validate(EKcert)];\ncompute PCRs hash from eventlog and PCRs;\nvalidate quote;\nsession_key = genkey();\nAKcert = CA_Certify(AKpub, data.ID, AKtbscert);\nticket = {vno, Encrypt_server_secret_key({timestamp,\n\t\t\tgettimeofday(),\n\t\t\tsession_key})} +S --> ST: TPM2_MakeCredential(EKpub, AKpub, session_key) +ST --> S: credentialBlob, secret +S -> C: credentialBlob, secret, ticket +C --> T: TPM2_ActivateCredential(AKhandle, EKhandle,\n\t\t\t\t\tcredentialBlob, secret) +T --> C: certInfo = session_key +C -> C: PoP = HMAC_session_key(ticket) +S -> C: Encrypt_session_key(stuff =\n\t\t\t\t\t\t{AKcert, data.for_client}) +C -> C: {AKcert, secrets} =\n\t\tDecrypt_session_key(stuff) +@enduml diff --git a/Attestation/Protocol-Three-Messages.png b/Attestation/Protocol-Three-Messages.png new file mode 100644 index 0000000..42c4ef7 Binary files /dev/null and b/Attestation/Protocol-Three-Messages.png differ diff --git a/Attestation/Protocol-Three-Messages.puml b/Attestation/Protocol-Three-Messages.puml new file mode 100644 index 0000000..a531c27 --- /dev/null +++ b/Attestation/Protocol-Three-Messages.puml @@ -0,0 +1,19 @@ +@startuml +participant TPM as T +participant Client as C +participant Server as S +participant ServerSimTPM as ST +title Three-message (1.5 round trips) attestation protocol w/ Proof-of-Possession +C -> C: timestamp = gettimeofday(); +C --> T: TPM2_Quote(AK, set-of-all-PCRs, timestamp) +T --> C: quote=Signed_AK({hash-of-PCRs, misc, timestamp}) +C -> S: [ID], EKpub, [EKcert], AKpub,\nPCRs, eventlog, timestamp, quote +S -> S: check that timestamp is recent;\ndata = Lookup(EKpub, [EKcert], [ID]);\n[Validate(EKcert)];\ncompute PCRs hash from eventlog and PCRs;\nvalidate quote;\nsession_key = genkey();\nAKcert = CA_Certify(AKpub, data.ID, AKtbscert);\nstuff = Encrypt_session_key({AKcert,\n\t\t\t\t\tdata.for_client}) +S --> ST: TPM2_MakeCredential(EKpub, AKpub, session_key) +ST --> S: credentialBlob, secret +S -> C: credentialBlob, secret, stuff +C --> T: TPM2_ActivateCredential(AKhandle, EKhandle,\n\t\t\t\t\tcredentialBlob, secret) +T --> C: certInfo = session_key +C -> C: {AKcert, secrets} =\n\t\tDecrypt_session_key(stuff); +C -> S: {AKcert, PoP = Digest(AKcert)} +@enduml diff --git a/Attestation/Protocol-Two-Messages.png b/Attestation/Protocol-Two-Messages.png new file mode 100644 index 0000000..8957dca Binary files /dev/null and b/Attestation/Protocol-Two-Messages.png differ diff --git a/Attestation/Protocol-Two-Messages.puml b/Attestation/Protocol-Two-Messages.puml new file mode 100644 index 0000000..05d20f2 --- /dev/null +++ b/Attestation/Protocol-Two-Messages.puml @@ -0,0 +1,18 @@ +@startuml +participant TPM as T +participant Client as C +participant Server as S +participant ServerSimTPM as ST +title Two-message (one round trip) attestation protocol +C -> C: timestamp = gettimeofday(); +C --> T: TPM2_Quote(AK, set-of-all-PCRs, timestamp) +T --> C: quote=Signed_AK({hash-of-PCRs, misc, timestamp}) +C -> S: [ID], EKpub, [EKcert], AKpub,\nPCRs, eventlog, timestamp, quote +S -> S: check that timestamp is recent;\ndata = Lookup(EKpub, [EKcert], [ID]);\n[Validate(EKcert)];\ncompute PCRs hash from eventlog and PCRs;\nvalidate quote;\nsession_key = genkey();\nAKcert = CA_Certify(AKpub, data.ID, AKtbscert);\nstuff = Encrypt_session_key({AKcert,\n\t\t\t\t\tdata.for_client}) +S --> ST: TPM2_MakeCredential(EKpub, AKpub, session_key) +ST --> S: credentialBlob, secret +S -> C: credentialBlob, secret, stuff +C --> T: TPM2_ActivateCredential(AKhandle, EKhandle,\n\t\t\t\t\tcredentialBlob, secret) +T --> C: certInfo = session_key +C -> C: {AKcert, secrets} =\n\t\tDecrypt_session_key(stuff); +@enduml diff --git a/Attestation/README.md b/Attestation/README.md index 0f214ec..0a6691b 100644 --- a/Attestation/README.md +++ b/Attestation/README.md @@ -12,29 +12,55 @@ A computer can use a TPM to demonstrate: Possible outputs of succesful attestation: - - encrypted filesystems getting unlocked with the help of an - attestation server + - authorize client to join its network - - other secrets (e.g., credentials for various authentication systems) + - delivery of configuration metadata to the client - - issuance of X.509 certificate(s) for TPM-resident public keys + - unlocking of storage / filesystems on the client - For servers these certificates would have `dNSName` subject - alternative names (SANs). + - delivery of various secrets, such credentials for various authentication systems: - For a user device such a certificate might have a subject name and/or - SANs identifying the user. + - issuance of X.509 certificate(s) for TPM-resident attestaion + public keys + + For servers these certificates would have `dNSName` subject + alternative names (SANs). + + For a user device such a certificate might have a subject name + and/or SANs identifying the user or device. + + - issuance of non-PKIX certificates (e.g., OpenSSH-style certificates) + + - issuance of Kerberos host-based service principal long-term keys + ("keytabs") + + - service account tokens + + - etc. + + - client state tracking + + - etc. Possible outputs of unsuccessful attestation: - alerting - diagnostics (e.g., which PCR extensions in the PCR quote and eventlog - are not recognized) + are not recognized, which then might be used to determine what + firmware / OS updates a client has installed, or that it has been + compromised) + +In this tutorial we'll focus on attestion of servers in an enterprise +environment. However, the concepts described here are applicable to +other environments, such as IoTs and personal devices, where the +attestation database could be hosted on a user's personal devices for +use in joining new devices to the user's set of devices, or for joining +new IoTs to the user's SOHO network. # Attestation Protocols -Attestation is done by a computer with a TPM interacting with an +Attestation is done by a client computer with a TPM interacting with an attestation service over a network. This requires a network protocol for attestation. @@ -91,6 +117,27 @@ EKpub and AKpub will happen via [`TPM2_MakeCredential()`](TPM2_MakeCredential.md) / [`TPM2_ActivateCredential()`](TPM2_ActivateCredential.md). +Note that the [`TPM2_Quote()`](TPM2_Quote.md) function produces a signed +message -- signed with a TPM-resident AK named by the caller (and to +which they have access), which would be the AK used in the attestation +protocol. + +The output of [`TPM2_Quote()`](TPM2_Quote.md) might be the only part of +a client's messages to the attestation service that include a signature +made with the AK, but integrity protection of everything else can be +implied (e.g., the eventlog and PCR values are used to reconstruct the +PCR digest signed in the quote). `TPM2_Quote()` signs more than just a +digest of the selected PCRs. `TPM2_Quote()` signs all of: + + - digest of selected PCRs + - caller-provided extra data (e.g., a cookie/nonce/timestamp/...), + - the TPM's firmware version number, + - `clock` (the TPM's time since startup), + - `resetCount` (an indirect indicator of reboots), + - `restartCount` (an indirect indicator of suspend/resume events) + - and `safe` (a boolean indicating whether the `clock` might have ever + gone backwards). + ## Binding of Other Keys to EKpub The semantics of [`TPM2_MakeCredential()`](TPM2_MakeCredential.md) / @@ -143,7 +190,9 @@ Let's start with few observations and security considerations: - Some replay protection or freshness indication for client requests is needed. A stateful method of doing this is to use a server-generated - nonce. A stateless method is to use a timestamp. + nonce (as an encrypted state cookie embedding a timestamp). A + stateless method is to use a timestamp and reject requests with old + timestamps. - Replay protection of server to client responses is mostly either not needed or implicitly provided by [`TPM2_MakeCredential()`](TMP2_MakeCredential.md) @@ -176,6 +225,33 @@ Let's start with few observations and security considerations: have to be sent may not fit on a URI local part or URI query parameters, therefore HTTP `POST` is the better option. +### Error Cases Not Shown + +Note that error cases are not shown in the protocols described below. + +Naturally, in case of error the attestation server will send a suitable +error message back to the client. + +### Databases, Log Sinks, and Dashboarding / Alerting Systems Not Shown + +In order to simplify the protocol diagrams below, interactions with +databases, log sinks, and alerting systems are not shown. + +A typical attestation service will, however, have interactions with +those components, some or all of which might even be remote: + + - attestation database + - log sinks + - dashboarding / alerting + +If an attestation service must be on the critical path for booting an +entire datacenter, it may be desirable for the attestation service to be +able to run with no remote dependencies, at least for some time. This +means, for example, that the attestation database should be locally +available and replicated/synchronized only during normal operation. It +also means that there should be a local log sink that can be sent to +upstream collectors during normal operation. + ### Single Round Trip Attestation Protocol Patterns An attestation protocol need not complete proof-of-possession @@ -195,11 +271,13 @@ protocol: ``` - CS0: Signed_AK({timestamp, [ID], EKpub, [EKcert], - AKpub, PCR_quote, eventlog}) + CS0: [ID], EKpub, [EKcert], AKpub, PCRs, eventlog, timestamp, + TPM2_Quote(AK, PCRs, extra_data)=Signed_AK({hash-of-PCRs, misc, extra_data}) SC0: {TPM2_MakeCredential(EKpub, AKpub, session_key), Encrypt_session_key({AKcert, filesystem_keys, etc.})} + + @@ -207,6 +285,11 @@ protocol: (`ID` might be, e.g., a hostname.) +![Protocol Diagram](Protocol-Two-Messages.png) + +(In this diagram we show the use of a TPM simulator on the server side +for implementing [`TPM2_MakeCredential()`](TPM2_MakeCredential.md).) + The server will validate that the `timestamp` is near the current time, the EKcert (if provided, else the EKpub), the signature using the asserted (but not yet bound to the EKpub) AKpub, then it will validate @@ -218,26 +301,67 @@ The client obtains those items IFF (if and only if) the AK is resident in the same TPM as the EK, courtesy of `TPM2_ActivateCredential()`'s semantics. -NOTE well that in this example it is *essential* that the AKcert not be -logged in any public place since otherwise an attacker can make and send -`CS0` using a non-TPM-resident AK and any TPM's EKpub/EKcert known to -the attacker, and then it may recover the AK certificate from the log in -spite of being unable to recover the AK certificate from `SC1`! +NOTE well that in single round trip attestation protocols using only +decrypt-only EKs it is *essential* that the AKcert not be logged in any +public place since otherwise an attacker can make and send `CS0` using a +non-TPM-resident AK and any TPM's EKpub/EKcert known to the attacker, +and then it may recover the AK certificate from the log in spite of +being unable to recover the AK certificate from `SC1`! Alternatively, a single round trip attestation protocol can be implemented as an optimization to a two round trip protocol when the AK is persisted both, in the client TPM and in the attestation service's database: - ``` - CS0: Signed_AK({timestamp, AKpub, PCR_quote, eventlog}) + CS0: timestamp, AKpub, PCRs, eventlog, + TPM2_Quote(AK, PCRs, extra_data)=Signed_AK({hash-of-PCRs, misc, extra_data}) SC0: {TPM2_MakeCredential(EKpub, AKpub, session_key), Encrypt_session_key({AKcert, filesystem_keys, etc.})} ``` +### Three-Message Attestation Protocol Patterns + +A single round trip protocol using encrypt-only EKpub will not +demonstrate proof of possession immediately, but later on when the +certified AK is used elsewhere. A proof-of-possession (PoP) may be +desirable anyways for monitoring and alerting purposes. + +``` + CS0: [ID], EKpub, [EKcert], AKpub, PCRs, eventlog, timestamp, + TPM2_Quote(AK, PCRs, extra_data)=Signed_AK({hash-of-PCRs, misc, extra_data}) + SC0: {TPM2_MakeCredential(EKpub, AKpub, session_key), + Encrypt_session_key({AKcert, filesystem_keys, etc.})} + CS1: AKcert, Signed_AK(AKcert) +``` + +![Protocol Diagram](Protocol-Three-Messages.png) + +(In this diagram we show the use of a TPM simulator on the server side +for implementing [`TPM2_MakeCredential()`](TPM2_MakeCredential.md).) + +NOTE well that in this protocol, like single round trip attestation +protocols using only decrypt-only EKs, it is *essential* that the AKcert +not be logged in any public place since otherwise an attacker can make +and send `CS0` using a non-TPM-resident AK and any TPM's EKpub/EKcert +known to the attacker, and then it may recover the AK certificate from +the log in spite of being unable to recover the AK certificate from +`SC1`! + +If such a protocol is instantiated over HTTP or TCP, it will really be +more like a two round trip protocol: + +``` + CS0: [ID], EKpub, [EKcert], AKpub, PCRs, eventlog, timestamp, + TPM2_Quote(AK, PCRs, extra_data)=Signed_AK({hash-of-PCRs, misc, extra_data}) + SC0: {TPM2_MakeCredential(EKpub, AKpub, session_key), + Encrypt_session_key({AKcert, filesystem_keys, etc.})} + CS1: AKcert, Signed_AK(AKcert) + SC1: +``` + ### Two Round Trip Stateless Attestation Protocol Patterns We can add a round trip to the protocol in the previous section to make @@ -252,11 +376,13 @@ back to the server rather than a secret key possesion of which is proven with symmetriclly-keyed cryptographic algorithms. ``` - CS0: Signed_AK({timestamp, [ID], EKpub, [EKcert], - AKpub, PCR_quote, eventlog}) + CS0: [ID], EKpub, [EKcert], AKpub, PCRs, eventlog, timestamp, + TPM2_Quote(AK, PCRs, extra_data)=Signed_AK({hash-of-PCRs, misc, extra_data}) SC0: {TPM2_MakeCredential(EKpub, AKpub, session_key), ticket} CS1: {ticket, MAC_session_key(CS0), CS0} SC1: Encrypt_session_key({AKcert, filesystem_keys, etc.}) + + ``` where `session_key` is an ephemeral secret symmetric authenticated @@ -267,6 +393,8 @@ encryption key, and `ticket` is an authenticated encrypted state cookie: MAC_session_key(CS0)})} ``` +![Protocol Diagram](Protocol-Four-Messages.png) + where `server_secret_key` is a key known only to the attestation service and `vno` identifies that key (in order to support key rotation without having to try authenticated decryption twice near key rotation events). @@ -309,6 +437,10 @@ An HTTP API binding for this protocol could look like: Response: SC1 ``` +Here the attestation happens in the first round trip, but the proof of +possession is completed in the second, and the delivery of secrets and +AKcert also happens in the second round trip. + ### Actual Protocols: ibmacs The [`IBM TPM Attestation Client Server`](https://sourceforge.net/projects/ibmtpm20acs/) @@ -358,7 +490,20 @@ to two round trips. ### Actual Protocols: safeboot.dev -(TBD) +``` + CS0: + SC0: nonce, PCR_list + CS1: [ID], EKpub, [EKcert], AKpub, PCRs, eventlog, nonce, + TPM2_Quote(AK, PCRs, extra_data)=Signed_AK({hash-of-PCRs, misc, extra_data}) + SC1: {TPM2_MakeCredential(EKpub, AKpub, session_key), + Encrypt_session_key({filesystem_keys})} +``` + +Nonce validation is currently not well-developed in Safeboot. +If a timestamp is used instead of a nonce, and if the client assumes all +PCRs are desired, then this becomes a one round trip protocol. + +An AKcert will be added to the Safeboot protocol soon. ### Actual Protocols: ... @@ -383,9 +528,8 @@ proof of possession non-interactively, whereas asymmetric encryption requires interaction to prove possession: ``` - CS0: Signed_AK({timestamp, [ID], EKpub, [EKcert], - AKpub, TPM2_Certify(EKpub, AKpub), - PCR_quote, eventlog}) + CS0: timestamp, [ID], EKpub, [EKcert], AKpub, PCRs, eventlog, + TPM2_Certify(EKpub, AKpub), TPM2_Quote() SC0: AKcert ``` @@ -393,11 +537,9 @@ If secrets need to be sent back, then a decrypt-only EK also neds to be used: ``` - CS0: Signed_AK({timestamp, [ID], - EKpub_signing, EKpub_encrypt, - [EKcert_signing], [EKcert_encrypt], - AKpub, TPM2_Certify(EKpub, AKpub), - PCR_quote, eventlog}) + CS0: timestamp, [ID], EKpub_signing, EKpub_encrypt, + [EKcert_signing], [EKcert_encrypt], AKpub, PCRs, eventlog, + TPM2_Certify(EKpub, AKpub), TPM2_Quote() SC0: {TPM2_MakeCredential(EKpub_encrypt, AKpub, session_key), Encrypt_session_key({AKcert, filesystem_keys, etc.})} ``` @@ -408,6 +550,7 @@ Attestation servers need to keep some long-term state: - binding of `EKpub` and `ID` - PCR validation profile(s) for each identified client + - resetCount (for reboot detection) Log-like attestation state: @@ -431,16 +574,138 @@ Things to log: attestation protocols above -- do not log AKcerts in public places when using single round trip attestation protocols!) -## Long-Term State Created by Attestation Services +## Long-Term State Created or Updated by Attestation Services -An attestation service might support creation of host<->EKpub -bindings on a first-come-first-served basis. + - An attestation service might support creation of host<->EKpub + bindings on a first-come-first-served basis. In this mode the + attestation server might validate an EKcert and that the desired + hostname has not been bound to an EK, then create the binding. -An attestation service might support deletion of host PCR validation -profiles that represent past states upon validation of PCR quotes using -newer profiles. This could be used to permit firmware and/or operating -system upgrades and then disallow downgrades after evidence of -successful upgrade. + - An attestation service might support deletion of host PCR validation + profiles that represent past states upon validation of PCR quotes + using newer profiles. This could be used to permit firmware and/or + operating system upgrades and then disallow downgrades after evidence + of successful upgrade. + + - An attestation service might keep track of client reboots so as to: + - revoke old AKcerts when the client reboots (but note that this is + really not necessary if we trust the client's TPM, since then the + previous AKs will never be usable again) + - alert if the reboot count ever goes backwards + +## Schema for Attestation Server Database + +A schema for the attestation server's database entries might look like: + +```JSON +{ + "EKpub": "", + "hostname": "", + "EKcert": "", + "previous_firmware_profile": "FWProfile0", + "current_firmware_profiles": ["FWProfile1", "FWProfile2", "..."], + "previous_operating_system_profiles": "OSProfile0", + "current_operating_system_profiles": ["OSProfile1", "OSProfile2", "..."], + "previous_PCRs": "<...>", + "proposed_PCRs": "<...>", + "ak_cert_template": "", + "secrets": "", + "resetCount": "" +} +``` + +The attestation server's database should have two lookup keys: + + - EKpub + - hostname + +The attestation server's database's entry for any client should provide, +de minimis: + + - a way to validate the root of trust measurements in the client's + quoted PCRs, for which two methods are possible: + - save the PCRs quoted last as the ones expected next time + - or, name profiles for validating firmware RTM PCRs and profiles + for validating operating system RTM PCRs + +A profile for validating PCRs should contain a set of expected extension +values for each of a set of PCRs. The attestation server can then check +that the eventlog submitted by the client lists exactly those extension +values and no others. PCR extension order in the eventlog probably +doesn't matter here. If multiple profiles are named, then one of those +must match -- this allows for upgrades and downgrades. + +```JSON +{ + "profile_name":"SomeProfile", + "values":[ + { + "PCR":0, + "values":["aaaaaaa","bbbbbb","..."] + }, + { + "PCR":1, + "values":["ccccccc","dddddd","..."] + } + ] +} +``` + +Using the PCR values from the previous attestation makes upgrades +tricky, probably requiring an authenticated and authorized administrator +to bless new PCR values after an upgrade. A client that presents a PCR +quote that does not match the previous one would cause the +`proposed_PCRs` field to be updated but otherwise could not continue, +then an administrator would confirm that the client just did a +firmware/OS upgrade and if so replace the `previous_PCRs` with the +`proposed_PCRs`, then the client could attempt attestation again. + +## Dealing with Secrets + +An attestation server might want to return storage/filesystem decryption +key-encryption-keys to a client. But one might not want to store those +keys in the clear on the attestation server. As well, one might want a +break-glass way to recover those secrets. + +For break-glass recover, the simplest thing to do is to store +`Encrypt_backupKey({EKpub, hostname, secrets})`, where `backupKey` is an +asymmetric key whose private key is stored offline (e.g., in a safe, or +in an offline HSM). To break the glass and recover the key, just bring +the ciphertext to the offline system where the private backup key is +kept, decrypt it, and then use the secrets manually to recover the +affected system. + +Here are some ideas for how to make an attestation client depend on the +attestation server giving it keys needed to continue booting after +successful attestation: + + - Store `TPM2_MakeCredential(EKpub, someObjectName, key0), Encrypt_key0(secrets)`. + + In this mode the server sends the client the stored data, then client + gets to recreate `someObject` (possibly by loading a saved object) on + its TPM so that the corresponding call to `TPM2_ActivateCredential()` + can succeed, then the client recovers `key0` and decrypts the + encrypted secrets. Here `someObject` can be trivial and need only + exist to make the `{Make,Activate}Credential` machinery work. + + TPM replacement and/or migration of a host from one physical system + to another can be implemented by learning the new system's TPM's + EKpub and using the offline `backupKey` to compute + `TPM2_MakeCredential(EKpub_new, someObjectName, key0)` and update the + host's entry. + + - Store a secret value that will be extended into an application PCR + that is used as a policy PCR for unsealing a persistent object stored + on the client's TPM. + + In this mode the server sends the client the secret PCR extension + value, and the client uses it to extend a PCR such that it can then + unseal the real storage / filesystem decryption keys. + + - A hybrid of the previous two options, where the server stores a + secret PCR extension value wrapped with `TPM2_MakeCredential()`. + +Other ideas? # References diff --git a/Attestation/TPM2_Quote.md b/Attestation/TPM2_Quote.md new file mode 100644 index 0000000..0059fb7 --- /dev/null +++ b/Attestation/TPM2_Quote.md @@ -0,0 +1,45 @@ +# `TPM2_Quote()` + +`TPM2_Quote()` computes a hash of the PCRs selected by the caller, and +signs that hash, some additional metadata, and any extra data provided +by the caller, with a signing key named by the caller. The caller must +have access to that key, naturally. + +The PCRs' values are NOT included in the quote produced by +`TPM2_Quote()`. Instead, an attestation service can review an unsigned +eventlog to ensure it leads to the same values as unsigned PCR values +also provided by the attestation client, and then the attestation +service can verify that the hash of the PCR values is indeed signed by +the quote supplied by the client. + +## Inputs + + - `TPMI_DH_OBJECT sigHandle` (handle for an AK) + - `TPM2B_DATA qualifyingData` (extra data) + - `TPMT_SIG_SCHEME inScheme` ("signing scheme to use if the schemefor signHandleis `TPM_ALG_NULL`") + - `TPML_PCR_SELECTION PCRselect` (set of PCRs to quote) + +## Outputs (success case) + + - `TPM2B_ATTEST quoted` + - `TPMT_SIGNATURE signature` + +Where `TPM2B_ATTEST` is basically a `TPMS_ATTEST`, which contains the +following fields: + + - `TPM_GENERATED magic` + - `TPMI_ST_ATTEST type` + - `TPM2B_NAME signer` (name of AK) + - `TPM2B_DATA extraData` ("external information supplied by caller") + - `TPMS_CLOCK_INFO clockInfo` ("Clock, resetCount, restartCount, and Safe") + - `UINT64 firmwareVersion` + - `TPMU_ATTEST attested`, a discriminated union with the + `TPMS_QUOTE_INFO` arm (indicated by the `TPM_ST_ATTEST_QUOTE` + discriminant value), which contains: + - `TPML_PCR_SELECTION pcrSelect` (the set of PCRs digested by `pcrDigest`) + - `TPM2B_DIGEST pcrDigest` (the digest of the PCRs indicated by `pcrSelect`) + +## References + + - [TCG TPM Library part 3: Commands, section 18.4](https://trustedcomputinggroup.org/wp-content/uploads/TCG_TPM2_r1p59_Part3_Commands_pub.pdf) +