mirror of
https://github.com/tpm2dev/tpm.dev.tutorials.git
synced 2024-12-22 09:42:11 +00:00
Merge pull request #7 from nicowilliams/master
Address comments by Trammell Hudson about attestation
This commit is contained in:
commit
8b064bcf4f
8 changed files with 406 additions and 39 deletions
BIN
Attestation/Protocol-Four-Messages.png
Normal file
BIN
Attestation/Protocol-Four-Messages.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 59 KiB |
20
Attestation/Protocol-Four-Messages.puml
Normal file
20
Attestation/Protocol-Four-Messages.puml
Normal file
|
@ -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
|
BIN
Attestation/Protocol-Three-Messages.png
Normal file
BIN
Attestation/Protocol-Three-Messages.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 54 KiB |
19
Attestation/Protocol-Three-Messages.puml
Normal file
19
Attestation/Protocol-Three-Messages.puml
Normal file
|
@ -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
|
BIN
Attestation/Protocol-Two-Messages.png
Normal file
BIN
Attestation/Protocol-Two-Messages.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 51 KiB |
18
Attestation/Protocol-Two-Messages.puml
Normal file
18
Attestation/Protocol-Two-Messages.puml
Normal file
|
@ -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
|
|
@ -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:
|
|||
```
|
||||
<client knows a priori what PCRs to quote, possibly all, saving a round trip>
|
||||
|
||||
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.})}
|
||||
|
||||
<extra_data includes timestamp>
|
||||
|
||||
<subsequent client use of AK w/ AKcert, or of credentials made
|
||||
available by dint of being able to access filesystems unlocked by
|
||||
SC0, demonstrate that the client has attested successfully>
|
||||
|
@ -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:
|
||||
|
||||
|
||||
```
|
||||
<having previously successfully enrolled AKpub and bound it to EKpub...>
|
||||
|
||||
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: <empty>
|
||||
```
|
||||
|
||||
### 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.})
|
||||
|
||||
<extra_data includes timestamp>
|
||||
```
|
||||
|
||||
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: <empty>
|
||||
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": "<EKpub>",
|
||||
"hostname": "<hostname>",
|
||||
"EKcert": "<EKcert in PEM, if available>",
|
||||
"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": "<AKCertTemplate>",
|
||||
"secrets": "<secrets>",
|
||||
"resetCount": "<resetCount value from last quote>"
|
||||
}
|
||||
```
|
||||
|
||||
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
|
||||
|
||||
|
|
45
Attestation/TPM2_Quote.md
Normal file
45
Attestation/TPM2_Quote.md
Normal file
|
@ -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)
|
||||
|
Loading…
Reference in a new issue