mirror of
https://github.com/tpm2dev/tpm.dev.tutorials.git
synced 2024-11-22 14:02: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:
|
Possible outputs of succesful attestation:
|
||||||
|
|
||||||
- encrypted filesystems getting unlocked with the help of an
|
- authorize client to join its network
|
||||||
attestation server
|
|
||||||
|
|
||||||
- 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
|
- delivery of various secrets, such credentials for various authentication systems:
|
||||||
alternative names (SANs).
|
|
||||||
|
|
||||||
For a user device such a certificate might have a subject name and/or
|
- issuance of X.509 certificate(s) for TPM-resident attestaion
|
||||||
SANs identifying the user.
|
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:
|
Possible outputs of unsuccessful attestation:
|
||||||
|
|
||||||
- alerting
|
- alerting
|
||||||
|
|
||||||
- diagnostics (e.g., which PCR extensions in the PCR quote and eventlog
|
- 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 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
|
attestation service over a network. This requires a network protocol
|
||||||
for attestation.
|
for attestation.
|
||||||
|
|
||||||
|
@ -91,6 +117,27 @@ EKpub and AKpub will happen via
|
||||||
[`TPM2_MakeCredential()`](TPM2_MakeCredential.md) /
|
[`TPM2_MakeCredential()`](TPM2_MakeCredential.md) /
|
||||||
[`TPM2_ActivateCredential()`](TPM2_ActivateCredential.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
|
## Binding of Other Keys to EKpub
|
||||||
|
|
||||||
The semantics of [`TPM2_MakeCredential()`](TPM2_MakeCredential.md) /
|
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
|
- Some replay protection or freshness indication for client requests is
|
||||||
needed. A stateful method of doing this is to use a server-generated
|
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
|
- Replay protection of server to client responses is mostly either not
|
||||||
needed or implicitly provided by [`TPM2_MakeCredential()`](TMP2_MakeCredential.md)
|
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
|
have to be sent may not fit on a URI local part or URI query
|
||||||
parameters, therefore HTTP `POST` is the better option.
|
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
|
### Single Round Trip Attestation Protocol Patterns
|
||||||
|
|
||||||
An attestation protocol need not complete proof-of-possession
|
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>
|
<client knows a priori what PCRs to quote, possibly all, saving a round trip>
|
||||||
|
|
||||||
CS0: Signed_AK({timestamp, [ID], EKpub, [EKcert],
|
CS0: [ID], EKpub, [EKcert], AKpub, PCRs, eventlog, timestamp,
|
||||||
AKpub, PCR_quote, eventlog})
|
TPM2_Quote(AK, PCRs, extra_data)=Signed_AK({hash-of-PCRs, misc, extra_data})
|
||||||
SC0: {TPM2_MakeCredential(EKpub, AKpub, session_key),
|
SC0: {TPM2_MakeCredential(EKpub, AKpub, session_key),
|
||||||
Encrypt_session_key({AKcert, filesystem_keys, etc.})}
|
Encrypt_session_key({AKcert, filesystem_keys, etc.})}
|
||||||
|
|
||||||
|
<extra_data includes timestamp>
|
||||||
|
|
||||||
<subsequent client use of AK w/ AKcert, or of credentials made
|
<subsequent client use of AK w/ AKcert, or of credentials made
|
||||||
available by dint of being able to access filesystems unlocked by
|
available by dint of being able to access filesystems unlocked by
|
||||||
SC0, demonstrate that the client has attested successfully>
|
SC0, demonstrate that the client has attested successfully>
|
||||||
|
@ -207,6 +285,11 @@ protocol:
|
||||||
|
|
||||||
(`ID` might be, e.g., a hostname.)
|
(`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 server will validate that the `timestamp` is near the current time,
|
||||||
the EKcert (if provided, else the EKpub), the signature using the
|
the EKcert (if provided, else the EKpub), the signature using the
|
||||||
asserted (but not yet bound to the EKpub) AKpub, then it will validate
|
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
|
in the same TPM as the EK, courtesy of `TPM2_ActivateCredential()`'s
|
||||||
semantics.
|
semantics.
|
||||||
|
|
||||||
NOTE well that in this example it is *essential* that the AKcert not be
|
NOTE well that in single round trip attestation protocols using only
|
||||||
logged in any public place since otherwise an attacker can make and send
|
decrypt-only EKs it is *essential* that the AKcert not be logged in any
|
||||||
`CS0` using a non-TPM-resident AK and any TPM's EKpub/EKcert known to
|
public place since otherwise an attacker can make and send `CS0` using a
|
||||||
the attacker, and then it may recover the AK certificate from the log in
|
non-TPM-resident AK and any TPM's EKpub/EKcert known to the attacker,
|
||||||
spite of being unable to recover the AK certificate from `SC1`!
|
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
|
Alternatively, a single round trip attestation protocol can be
|
||||||
implemented as an optimization to a two round trip protocol when the AK
|
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
|
is persisted both, in the client TPM and in the attestation service's
|
||||||
database:
|
database:
|
||||||
|
|
||||||
|
|
||||||
```
|
```
|
||||||
<having previously successfully enrolled AKpub and bound it to EKpub...>
|
<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),
|
SC0: {TPM2_MakeCredential(EKpub, AKpub, session_key),
|
||||||
Encrypt_session_key({AKcert, filesystem_keys, etc.})}
|
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
|
### Two Round Trip Stateless Attestation Protocol Patterns
|
||||||
|
|
||||||
We can add a round trip to the protocol in the previous section to make
|
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.
|
with symmetriclly-keyed cryptographic algorithms.
|
||||||
|
|
||||||
```
|
```
|
||||||
CS0: Signed_AK({timestamp, [ID], EKpub, [EKcert],
|
CS0: [ID], EKpub, [EKcert], AKpub, PCRs, eventlog, timestamp,
|
||||||
AKpub, PCR_quote, eventlog})
|
TPM2_Quote(AK, PCRs, extra_data)=Signed_AK({hash-of-PCRs, misc, extra_data})
|
||||||
SC0: {TPM2_MakeCredential(EKpub, AKpub, session_key), ticket}
|
SC0: {TPM2_MakeCredential(EKpub, AKpub, session_key), ticket}
|
||||||
CS1: {ticket, MAC_session_key(CS0), CS0}
|
CS1: {ticket, MAC_session_key(CS0), CS0}
|
||||||
SC1: Encrypt_session_key({AKcert, filesystem_keys, etc.})
|
SC1: Encrypt_session_key({AKcert, filesystem_keys, etc.})
|
||||||
|
|
||||||
|
<extra_data includes timestamp>
|
||||||
```
|
```
|
||||||
|
|
||||||
where `session_key` is an ephemeral secret symmetric authenticated
|
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)})}
|
MAC_session_key(CS0)})}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
![Protocol Diagram](Protocol-Four-Messages.png)
|
||||||
|
|
||||||
where `server_secret_key` is a key known only to the attestation service
|
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
|
and `vno` identifies that key (in order to support key rotation without
|
||||||
having to try authenticated decryption twice near key rotation events).
|
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
|
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
|
### Actual Protocols: ibmacs
|
||||||
|
|
||||||
The [`IBM TPM Attestation Client Server`](https://sourceforge.net/projects/ibmtpm20acs/)
|
The [`IBM TPM Attestation Client Server`](https://sourceforge.net/projects/ibmtpm20acs/)
|
||||||
|
@ -358,7 +490,20 @@ to two round trips.
|
||||||
|
|
||||||
### Actual Protocols: safeboot.dev
|
### 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: ...
|
### Actual Protocols: ...
|
||||||
|
|
||||||
|
@ -383,9 +528,8 @@ proof of possession non-interactively, whereas asymmetric encryption
|
||||||
requires interaction to prove possession:
|
requires interaction to prove possession:
|
||||||
|
|
||||||
```
|
```
|
||||||
CS0: Signed_AK({timestamp, [ID], EKpub, [EKcert],
|
CS0: timestamp, [ID], EKpub, [EKcert], AKpub, PCRs, eventlog,
|
||||||
AKpub, TPM2_Certify(EKpub, AKpub),
|
TPM2_Certify(EKpub, AKpub), TPM2_Quote()
|
||||||
PCR_quote, eventlog})
|
|
||||||
SC0: AKcert
|
SC0: AKcert
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -393,11 +537,9 @@ If secrets need to be sent back, then a decrypt-only EK also neds to be
|
||||||
used:
|
used:
|
||||||
|
|
||||||
```
|
```
|
||||||
CS0: Signed_AK({timestamp, [ID],
|
CS0: timestamp, [ID], EKpub_signing, EKpub_encrypt,
|
||||||
EKpub_signing, EKpub_encrypt,
|
[EKcert_signing], [EKcert_encrypt], AKpub, PCRs, eventlog,
|
||||||
[EKcert_signing], [EKcert_encrypt],
|
TPM2_Certify(EKpub, AKpub), TPM2_Quote()
|
||||||
AKpub, TPM2_Certify(EKpub, AKpub),
|
|
||||||
PCR_quote, eventlog})
|
|
||||||
SC0: {TPM2_MakeCredential(EKpub_encrypt, AKpub, session_key),
|
SC0: {TPM2_MakeCredential(EKpub_encrypt, AKpub, session_key),
|
||||||
Encrypt_session_key({AKcert, filesystem_keys, etc.})}
|
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`
|
- binding of `EKpub` and `ID`
|
||||||
- PCR validation profile(s) for each identified client
|
- PCR validation profile(s) for each identified client
|
||||||
|
- resetCount (for reboot detection)
|
||||||
|
|
||||||
Log-like attestation state:
|
Log-like attestation state:
|
||||||
|
|
||||||
|
@ -431,16 +574,138 @@ Things to log:
|
||||||
attestation protocols above -- do not log AKcerts in public places
|
attestation protocols above -- do not log AKcerts in public places
|
||||||
when using single round trip attestation protocols!)
|
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
|
- An attestation service might support creation of host<->EKpub
|
||||||
bindings on a first-come-first-served basis.
|
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
|
- An attestation service might support deletion of host PCR validation
|
||||||
profiles that represent past states upon validation of PCR quotes using
|
profiles that represent past states upon validation of PCR quotes
|
||||||
newer profiles. This could be used to permit firmware and/or operating
|
using newer profiles. This could be used to permit firmware and/or
|
||||||
system upgrades and then disallow downgrades after evidence of
|
operating system upgrades and then disallow downgrades after evidence
|
||||||
successful upgrade.
|
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
|
# 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